1. 動態代理分類
動態代理的兩種實現方式:1)JDK動態代理;2)CGLIB動態代理
2. JDK動態代理Demo
JDK動態代理所用到的代理類在程序調用到代理類對象時才由JVM真正創建,JVM根據傳進來的 業務實現類對象 以及 方法名 ,動態地創建了一個代理類的class文件並被字節碼引擎執行,然后通過該代理類對象進行方法調用。我們需要做的,只需指定代理類的預處理、調用后操作即可。
1. 定義User接口
public interface User { public void login(); public void logout(); }
2. 分別實現Student類和administrator類
1 // Student類 2 public class Student implements User { 3 4 String Name; 5 6 @Override 7 public void login() { 8 System.out.println("Student login!"); 9 } 10 11 @Override 12 public void logout() { 13 System.out.println("Student logout!"); 14 } 15 16 } 17 18 // administrator類 19 public class Administrator implements User{ 20 21 String Name; 22 23 @Override 24 public void login() { 25 System.out.println("Administrator login!"); 26 } 27 28 @Override 29 public void logout() { 30 System.out.println("Administrator logout!"); 31 } 32 33 }
3. 實現 調用管理接口InvocationHandler 創建動態代理類
1 public class LoginProxy implements InvocationHandler { 2 3 private Object user; // 業務實現類對象,用來調用具體的業務方法 4 5 6 /** 7 * 包裝調用方法:進行預處理、調用后處理 8 */ 9 @Override 10 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 11 // TODO Auto-generated method stub 12 13 // 根據傳入user所屬類為用戶分配權限 14 if(user.getClass() == Student.class) { 15 16 System.out.println("獲取管理員權限失敗!"); 17 18 }else if(user.getClass() == Administrator.class) { 19 20 method.invoke(user, args); 21 22 }else { 23 System.out.println("失敗!"); 24 } 25 26 return null; 27 } 28 29 /** 30 * 綁定業務對象並返回一個代理類 31 */ 32 public Object bind(Object user) { 33 34 this.user = user; //接收業務實現類對象參數 35 36 //通過反射機制,創建一個代理類對象實例並返回。用戶進行方法調用時使用 37 //創建代理對象時,需要傳遞該業務類的類加載器(用來獲取業務實現類的元數據,在包裝方法是調用真正的業務方法)、接口、handler實現類 38 return Proxy.newProxyInstance(user.getClass().getClassLoader(), 39 user.getClass().getInterfaces(), this); 40 41 } 42 43 44 }
4. 在使用時,首先創建一個業務實現類對象和一個代理類對象,然后定義接口引用(這里使用向上轉型)並用代理對象.bind(業務實現類對象)的返回值進行賦值。最后通過接口引用調用業務方法即可。(接口引用真正指向的是一個綁定了業務類的代理類對象,所以通過接口方法名調用的是被代理的方法們)
public class Client { public static void main(String[] args) { // TODO Auto-generated method stub // student用戶 User student = new Student(); LoginProxy handler = new LoginProxy(); User user = (User) handler.bind(student); user.login(); // admin用戶 User admin = new Administrator(); LoginProxy handler2 = new LoginProxy(); User user2 = (User) handler2.bind(admin); user2.login(); } }
5. 查看命令行輸出
1 獲取管理員權限失敗! 2 Administrator login!
JDK動態代理的代理對象在創建時,需要使用業務實現類所實現的接口作為參數(因為在后面代理方法時需要根據接口內的方法名進行調用)。如果業務實現類是沒有實現接口而是直接定義業務方法的話,就無法使用JDK動態代理了。並且,如果業務實現類中新增了接口中沒有的方法,這些方法是無法被代理的(因為無法被調用)。
3. CGLIB動態代理Demo
...先空着
4. 比較
JDK動態代理是通過接口中的方法名,在動態生成的代理類中調用業務實現類的同名方法;
CGlib動態代理是通過繼承業務類,生成的動態代理類是業務類的子類,通過重寫業務方法進行代理;
參考:https://www.cnblogs.com/ygj0930/p/6542259.html
http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html
http://www.360doc.com/content/14/0801/14/1073512_398598312.shtml