一、代理模式
代理,顧名思義可以簡單理解為代為管理,代理模式就是為其他對象提供額外服務,控制訪問(前置處理),或做善后處理(后置處理)。有了代理之后,可以在原來功能的基礎上由代理完成另外一部分事情。
常見的代理模式有:
-
-
- 靜態代理:這種代理模式需要代理對象和目標對象實現相同的接口。可以在不修改目標對象的基礎上擴展功能。
- 缺點:靜態代理由於需要和目標對象實現相同的接口,當代理對象變多的時候代理類就會跟着增加,而且一旦更改了接口,那么目標對象和代理對象都要同時做出調整,不方便管理。
- 動態代理:代理對象不需要實現目標對象接口,通過JAVA的API動態生成目標對象的代理對象。Proxy.newProxyInstance(。。。),其中有三個參數:
- ClassLoader loader:目標對象的類加載器
- Class<?>[] interfaces:目標對象的接口類型
- InvocationHandler h:事件處理函數,實現對目標對象的操作。
- CGLIB動態代理:也叫作子類代理,它是在內存中構建一個子類對象從而實現對目標對象功能的擴展。
- JDK的動態代理有一個限制,就是使用動態代理的對象必須實現一個或多個接口,如果想代理沒有實現接口的類,就可以使用Cglib實現.
- Cglib是一個強大的高性能的代碼生成包,它可以在運行期擴展java類與實現java接口.它廣泛的被許多AOP的框架使用,例如Spring AOP和synaop,為他們提供方法的interception(攔截)
- Cglib包的底層是通過使用一個小而塊的字節碼處理框架ASM來轉換字節碼並生成新的類.不鼓勵直接使用ASM,因為它要求你必須對JVM內部結構包括class文件的格式和指令集都很熟悉.
- 靜態代理:這種代理模式需要代理對象和目標對象實現相同的接口。可以在不修改目標對象的基礎上擴展功能。
-
二、靜態代理(需要接口)
靜態代理需要目標對象和代理對象實現相同的接口:
UserDaoInterface接口類:
1 public interface UserDaoInterface { 2 public void save(); 3 }
目標對象:
1 public class UserDao implements UserDaoInterface { 2 public void save() { 3 System.out.println("保存用戶信息中。。。。"); 4 } 5 }
代理對象:
1 /** 2 * 代理對象,和目標對象實現相同接口 3 */ 4 public class UserDaoProxy implements UserDaoInterface { 5 private UserDaoInterface userDao; 6 7 public UserDaoProxy(UserDaoInterface userDao) { 8 this.userDao = userDao; 9 } 10 11 public void save() { 12 System.out.println("開始保存"); 13 userDao.save(); 14 System.out.println("保存成功"); 15 } 16 }
測試類:
1 public class Test { 2 @org.junit.jupiter.api.Test 3 public void testDemo(){ 4 System.out.println("靜態代理"); 5 //獲取對象 6 UserDaoInterface userDao = new UserDaoProxy(new UserDao()); 7 userDao.save(); 8 } 9 }
實現結果:
如果要增加接口的方法,目標對象和代理對象類都需要修改。
三、動態代理(需要接口)
動態代理,代理對象無需刻意實現目標對象接口。
接口類
1 public interface UserDaoInterface { 2 public void save(); 3 }
目標類
1 public class UserDao implements UserDaoInterface { 2 public void save() { 3 System.out.println("保存用戶信息中。。。。"); 4 } 5 }
代理類(動態代理,代理類沒有實現和目標對象一樣的接口 而是通過javaAPI在內存中為我們動態創建了一個代理對象)
1 /** 2 * 代理工廠類 3 */ 4 public class ProxyFactory { 5 private Object obj; 6 7 public ProxyFactory(Object obj) { 8 this.obj = obj; 9 } 10 11 public Object getInstance(){ 12 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), 13 obj.getClass().getInterfaces(), 14 new InvocationHandler() { 15 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 16 System.out.println("開始保存"); 17 Object returnObject = method.invoke(obj,args); 18 System.out.println("保存成功"); 19 return returnObject; 20 } 21 }); 22 } 23 }
測試類:
1 public class Test { 2 @org.junit.jupiter.api.Test 3 public void testDemo(){ 4 System.out.println("動態代理"); 5 UserDaoInterface target = new UserDao(); 6 UserDaoInterface proxy =(UserDaoInterface) new ProxyFactory(target).getInstance(); 7 proxy.save(); 8 System.out.println("原生對象:"+target.getClass()); 9 System.out.println("代理對象:"+proxy.getClass()); 10 } 11 }
運行結果:
從結果中我們可以看出返回的是一個javaAPI的代理對象。
四、CGLIB代理(無需接口)
CGLIB代理不需要目標對象有實現接口,它通過構建目標對象的子類對目標功能進行擴展
目標對象類:
1 public class UserDao{ 2 public void save(){ 3 System.out.println("保存用戶信息"); 4 } 5 }
代理對象類:
1 public class CglibProxy implements MethodInterceptor { 2 3 private Object target; 4 5 public CglibProxy(Object target) { 6 this.target = target; 7 } 8 9 //給目標對象創建代理對象 10 public Object getProxyInstance(){ 11 /** 12 * 1.工具類,允許為非接口類型創建一個Java代理。Enhancer動態創建了給定類型的子類但是攔截了所有的方法。 13 * 和Proxy不一樣的是,不管是接口還是類他都能正常工作 14 */ 15 Enhancer en = new Enhancer(); 16 /** 17 * 2.設置父類 18 */ 19 en.setSuperclass(target.getClass()); 20 /** 21 * 3.設置回掉函數(因為MethodInterceptor繼承了Callback類,默認執行intercept方法) 22 */ 23 en.setCallback(this); 24 /** 25 * 4.創建子類 26 */ 27 return en.create(); 28 } 29 30 public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { 31 System.out.println("開始保存"); 32 Object returnObject = method.invoke(target,objects); 33 System.out.println("保存結束"); 34 return returnObject; 35 } 36 }
測 試類:
1 public class Test { 2 @org.junit.jupiter.api.Test 3 public void testDemo(){ 4 System.out.println("cglib代理"); 5 UserDao userDao =(UserDao) new CglibProxy(new UserDao()).getProxyInstance(); 6 userDao.save(); 7 } 8 }
運行結果: