4(實戰(zhàn)):靜態(tài)代理+ JDK/CGLIB 動態(tài)代理(文末有項目連接)

1:什么是代理模式
代理模式是一種比較好理解的設(shè)計模式。
我們使用代理對象來代替真實對象的訪問,這樣子就可以在不修改原目標(biāo)對象的前提下,

提供額外的功能操作,擴展目標(biāo)對象的功能。
2:靜態(tài)代理
實際應(yīng)用場景非常少

靜態(tài)代理中:我們對目標(biāo)對象的每個方法的增強都是手動完成的
如:某個接口一旦新增了方法,代理對象和目標(biāo)對象都要進(jìn)行修改 

從JVM層面上:靜態(tài)代理就是在編譯時將接口、實現(xiàn)類、代理類變成一個個class文件,

1:定義一個接口和其實現(xiàn)類
2:創(chuàng)建一個代理類同樣實現(xiàn)這個接口
3:將目標(biāo)對象注入到代理類,然后在代理類的對應(yīng)方法 調(diào)用目標(biāo)類中的方法。
    我們就可以通過代理類屏蔽對目標(biāo)對象的訪問,并且可以在目標(biāo)方法執(zhí)行前后做一些自己的事情
3:動態(tài)代理
相對于靜態(tài)代理來說,動態(tài)代理更加靈活。
我們不需要針對每個目標(biāo)都獨立創(chuàng)建一個個代理類,并且也不需要我們必須實現(xiàn)接口;

從JVM角度來說,動態(tài)代碼在運行時動態(tài)生成類字節(jié)碼,并加重到JVM中的。

其中Spring AOP 和 RPC框架的實際都是依賴離開動態(tài)代理;

動態(tài)代理又分  JDK動態(tài)代理  和 CGLIB動態(tài)代理
4:JDK動態(tài)代理
Spring AOP 中默認(rèn)的代理方式   注意:只能代理實現(xiàn)了接口的類

具體調(diào)用流程:
    在通過Proxy類的 newProxyInstance()創(chuàng)建的代理對象調(diào)用方法的時候,
    實際會調(diào)用到實現(xiàn)InvocationHandler類的 invoke()方法。
    可以在 invoke()方法自定義處理邏輯。

 具體實現(xiàn)流程
    1:定義一個接口及其實現(xiàn)類;
    2:通過 Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)  創(chuàng)建代理對象
    3:自定義InvocationHandler 并重寫 invoke方法,
        在invoke方法中調(diào)用被代理類的的方法并自定義一些處理邏輯。

Proxy類中使用頻率最高的方法是:newProxyInstance() 主要用于生成一個代理對象

newProxyInstance方法中的三個參數(shù)
    1:loader:類加載器 用于加載代理對象;
    2:interfaces:被代理的一些接口;
    3:h:實現(xiàn)了InvocationHandler 接口的對象;
     public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 
        throws IllegalArgumentException 
        { ...... }
       

自定義InvocationHandler類中的 invoke 為反射方法

invoke方法中的三個參數(shù)
    1:proxy:動態(tài)生成的代理類
    2:method:與代理類對象調(diào)用的方法相對應(yīng)
    3:args:當(dāng)前method方法的參數(shù)
      public interface InvocationHandler {
        /** * 當(dāng)你使用代理對象調(diào)用方法的時候?qū)嶋H會調(diào)用到這個方法 */ 
        public Object invoke(Object proxy, Method method, Object[] args) 
         throws Throwable; 
    }

5:CFLIB動態(tài)代理
JDK動態(tài)代理有一個致命的問題:只能代理實現(xiàn)了接口的類

GCLIB通過繼承的方式實現(xiàn)代理,
例如在Spring中的AOP模塊中:如果目標(biāo)對象實現(xiàn)了接口,則默認(rèn)采用JDK動態(tài)代理,否則使用CGLIB動態(tài)代理。

具體調(diào)用流程:
    在通過Enhancer類的 create()創(chuàng)建的代理對象調(diào)用方法的時候,
    實際會調(diào)用到實現(xiàn)MethodInterceptor 類的intercept()方法。
    可以在 intercept()方法自定義處理邏輯。

 具體實現(xiàn)流程
    1:定義一個類;
    2:通過 Enhancer 類的create() 創(chuàng)建代理類
    3:自定義MethodInterceptor 并重寫 intercept方法,
        在intercept方法中調(diào)用被代理類的的方法并自定義一些處理邏輯。

Enhancer類 為cglib.proxy.Enhancer 該包下的 動態(tài)代理增強類
    // 創(chuàng)建動態(tài)代理增強類
    Enhancer enhancer = new Enhancer();
    // 設(shè)置類加載器
    enhancer.setClassLoader(clazz.getClassLoader());/
    // 設(shè)置被代理類
    enhancer.setSuperclass(clazz);
    // 設(shè)置方法攔截器
    enhancer.setCallback(new MyMethodInterceptor());
    // 創(chuàng)建代理類
    return enhancer.create();

自定義MyMethodInterceptor 類中的  intercept 方法
 
 intercept 方法中的四個參數(shù):
  1:obj  :    被代理的對象(需要增強的對象)
  2:method : 被攔截的方法(需要增強的方法)
  3:objects : 方法入?yún)?  4:methodProxy :用于調(diào)用原始方法
    public interface MethodInterceptor extends Callback{ 
    // 攔截被代理類中的方法 
    public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy)
        throws Throwable;
    }    
6:靜態(tài)代理和動態(tài)代理的區(qū)別總結(jié)
靈活性:
    靜態(tài)代理中接口一旦新增加方法,目標(biāo)對象和代理對象都要進(jìn)行修改,這是非常麻煩的;
    動態(tài)代理更加靈活,可以直接代理實現(xiàn)類,并不需要針對每一個目標(biāo)類都創(chuàng)建一個代理類。

JVM層面:
    靜態(tài)代理在編譯時就將接口、實現(xiàn)類、代理類這些變成一個個實際的class文件
    動態(tài)代理在運行期動態(tài)生成類字節(jié)碼 并 加載到JVM中
7:JDK動態(tài)代理 和 CGLib動態(tài)代理 區(qū)別
1:JDK動態(tài)代理是?帶的,CGlib需要引?第三?包

2:JDK動態(tài)代理,要求?標(biāo)對象實現(xiàn)?個接?,
    但是有時候?標(biāo)對象只是?個單獨的對象,并沒有實現(xiàn)任何的接?,這個時候就可以?CGLib動態(tài)代理

3:CGLib動態(tài)代理,它是在內(nèi)存中構(gòu)建?個?類對象從?實現(xiàn)對?標(biāo)對象功能的擴展
    CGLib動態(tài)代理基于繼承來實現(xiàn)代理,所以?法對final類、private?法和static?法實現(xiàn)代理

Spring AOP中的代理使?的默認(rèn)策略?
    如果?標(biāo)對象實現(xiàn)了接?,則默認(rèn)采?JDK動態(tài)代理
    如果?標(biāo)對象沒有實現(xiàn)接?,則采?CgLib進(jìn)?動態(tài)代理
    如果?標(biāo)對象實現(xiàn)了接?,程序??依舊可以指定使?CGlib動態(tài)代理

項目連接

請配合項目代碼食用效果更佳:
項目地址:
https://github.com/hesuijin/rpc-project
Git下載地址:
https://github.com.cnpmjs.org/hesuijin/rpc-project.git

rpc-project-demo模塊下  proxyDemo包      
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容