理解三種代理模式


一、代理模式

  代理,顧名思義可以簡單理解為代為管理,代理模式就是為其他對象提供額外服務,控制訪問(前置處理),或做善后處理(后置處理)。有了代理之后,可以在原來功能的基礎上由代理完成另外一部分事情

  常見的代理模式有:

      • 靜態代理:這種代理模式需要代理對象和目標對象實現相同的接口。可以在不修改目標對象的基礎上擴展功能。
        • 缺點:靜態代理由於需要和目標對象實現相同的接口,當代理對象變多的時候代理類就會跟着增加,而且一旦更改了接口,那么目標對象和代理對象都要同時做出調整,不方便管理。
      • 動態代理:代理對象不需要實現目標對象接口,通過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 }

 

  運行結果:

   

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM