JDK和CGLIB生成動態代理類的區別

2020-11-06 smile蒲公英QQ

關於動態代理和靜態代理

當一個對象(客戶端)不能或者不想直接引用另一個對象(目標對象),這時可以應用代理模式在這兩者之間構建一個橋梁--代理對象。

按照代理對象的創建時期不同,可以分為兩種:

靜態代理:事先寫好代理對象類,在程序發布前就已經存在了;

動態代理:應用程式發布後,通過動態創建代理對象。

靜態代理其實就是一個典型的代理模式實現,在代理類中包裝一個被代理對象,然後影響被代理對象的行為,比較簡單,代碼就不放了。

其中動態代理又可分為:JDK動態代理和CGLIB代理。

1.JDK動態代理

此時代理對象和目標對象實現了相同的接口,目標對象作為代理對象的一個屬性,具體接口實現中,可以在調用目標對象相應方法前後加上其他業務處理邏輯。

代理模式在實際使用時需要指定具體的目標對象,如果為每個類都添加一個代理類的話,會導致類很多,同時如果不知道具體類的話,怎樣實現代理模式呢?這就引出動態代理。

JDK動態代理只能針對實現了接口的類生成代理。

2.CGLIB代理

CGLIB(CODE GENERLIZE LIBRARY)代理是針對類實現代理,

主要是對指定的類生成一個子類,覆蓋其中的所有方法,所以該類或方法不能聲明稱final的。

JDK動態代理和CGLIB代理生成的區別

JDK動態代理只能對實現了接口的類生成代理,而不能針對類 。
CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法 。
因為是繼承,所以該類或方法最好不要聲明成final ,final可以阻止繼承和多態。

PS:final 所修飾的數據具有「終態」的特徵,表示「最終的」意思:

  • final 修飾的類不能被繼承。
  • final 修飾的方法不能被子類重寫。
  • final 修飾的變量(成員變量或局部變量)即成為常量,只能賦值一次。
  • final 修飾的成員變量必須在聲明的同時賦值,如果在聲明的時候沒有賦值,那麼只有 一次賦值的機會,而且只能在構造方法中顯式賦值,然後才能使用。
  • final 修飾的局部變量可以只聲明不賦值,然後再進行一次性的賦值。

參考代碼

CGLIB:

public Object createProxyObject(Object obj) {     this.targetObject = obj;     Enhancer enhancer = new Enhancer();     enhancer.setSuperclass(obj.getClass());     enhancer.setCallback(this);     Object proxyObj = enhancer.create();     return proxyObj;// 返回代理對象,返回的對象其實就是一個封裝了「實現類」的代理類,是實現類的實例。 } 

JDK:

public Object newProxy(Object targetObject) {// 將目標對象傳入進行代理     this.targetObject = targetObject;  <br data-filtered="filtered">    //注意這個方法的參數,後面是類實現的接口    return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),             targetObject.getClass().getInterfaces(), this);// 返回代理對象 }

在代碼中可以看到,在生成代理類時,傳遞的是實現類所實現的接口 targetObject.getClass().getInterfaces(),所以JDK只能對於接口進行做代理。如果換成類的話,則會拋java.lang.ClassCastException異常

在Spring的源碼中,可以看到很多生成代理類的代碼。

動態代理的應用

AOP(Aspect-OrientedProgramming,面向切面編程),AOP包括切面(aspect)、通知(advice)、連接點(joinpoint),實現方式就是通過對目標對象的代理在連接點前後加入通知,完成統一的切面操作

實現AOP的技術,主要分為兩大類:

一是採用動態代理技術,利用截取消息的方式,對該消息進行裝飾,以取代原有對象行為的執行;

二是採用靜態織入的方式,引入特定的語法創建「方面」,從而使得編譯器可以在編譯期間織入有關「方面」的代碼。

Spring提供了兩種方式來生成代理對象: JDKProxy和Cglib,具體使用哪種方式生成由AopProxyFactory根據AdvisedSupport對象的配置來決定。

默認的策略是如果目標類是接口,則使用JDK動態代理技術,如果目標對象沒有實現接口,則默認會採用CGLIB代理。

如果目標對象實現了接口,可以強制使用CGLIB實現代理(添加CGLIB庫,並在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。

相關焦點

  • 聊聊JDK和CGLIB動態代理的原理和區別
    原文連結:https://blog.csdn.net/yhl_jxy/article/details/80635012一 JDK和CGLIB動態代理原理1、JDK動態代理利用攔截器(攔截器必須實現InvocationHanlder)加上反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler
  • 你必須會的 JDK 動態代理和 CGLIB 動態代理
    ,代理類和目標類都實現相同的接口。JDK 動態代理動態代理類與靜態代理類最主要不同的是,代理類的字節碼不是在程序運行前生成的,而是在程序運行時再虛擬機中程序自動創建的。 繼續用上面 Cat 類和 Animal 接口實現 JDK 動態代理。
  • cglib動態代理對類沒有任何限制嗎?
    大家都知道,動態代理常見的兩種實現方式,jdk的動態代理和cglib動態代理,而jdk動態代理必須基於接口,cglib沒有這樣的要求。之前我們討論過jdk動態代理為什麼必須基於接口,傳送門:那麼cglib動態代理真的沒有任何限制嗎?
  • Java中的原生動態代理和CGLIB動態代理的原理
    靜態代理的代理關係在編譯時就確定了,而動態代理的代理關係是在編譯期確定的。靜態代理實現簡單,適合於代理類較少且確定的情況,而動態代理則給我們提供了更大的靈活性。:JDK原生動態代理和CGLIB動態代理。
  • 終於搞懂靜態代理、JDK和CGLIB動態代理,面試再也不慌了
    proxyCar=new ProxyCar();// proxyCar.move(); 聚合代理:代理類和被代理類,都要實現相同接口,被代理類作為代理類的成員變量,通過構造器傳入代理類,在代理類中調用被代理類方法/** * 一個類有一個類的實體引用(類中的類),則它稱為聚合 */public class ProxyCar2
  • 9分鐘帶你搞懂代理模式、靜態代理、JDK+CGLIB動態代理
    學會了動態代理之後,對於我們理解和學習各種框架的原理也非常有幫助。,它允許我們在運行時對字節碼進行修改和動態生成。 另外, CGLIB 動態代理是通過生成一個被代理類的子類來攔截被代理類的方法調用,因此不能代理聲明為 final 類型的類和方法。
  • Java動態代理之一CGLIB詳解
    在上篇文章《Java代理模式及動態代理詳解》中我們介紹了Java中的靜態代理模式與動態代理模式,並以JDK原生動態代理作為示例進行講解。本篇文章我們來介紹一下基於CGLIB實現的動態代理,並與原生動態代理進行對比。
  • 深入了解面向切面編程 Spring底層兩種動態代理實現原理及區別
    通過cglib的jar包實現動態代理,該方法只需要對目標對象繼承即可Spring支持兩種方法,那麼我們在使用spring進行動態代理時究竟使用的哪一種方法呢?spring優先支持實現接口的方式,如果沒有接口則使用cglib方式。下面我們看一看這兩種方法有什麼區別。
  • java動態代理為什麼需要基於接口
    面試的時候,常常面試官會問spring 的aop底層原理,而aop的底層原理就是動態代理,每個java程式設計師基本都能耳熟能詳,對jdk動態代理和cglib動態代理的區別也瞭然於胸,jdk動態代理只能基於接口,而cglib並不需要。
  • 一文看讀懂反向代理
    2.2 代理的分類靜態代理:靜態代理需要為每個被代理的類創建一個代理類,當被代理的類過多的時候,就會導致代理類的增多,不便於維護。動態代理:動態代理不需要為每個被代理的類創建一個代理類,只需要一個全局的代理類,在需要的時候動態生成,便於維護。
  • 一看讀懂反向代理
    2.2 代理的分類靜態代理:靜態代理需要為每個被代理的類創建一個代理類,當被代理的類過多的時候,就會導致代理類的增多,不便於維護。動態代理:動態代理不需要為每個被代理的類創建一個代理類,只需要一個全局的代理類,在需要的時候動態生成,便於維護。
  • 終於有人把 java代理 講清楚了,萬字詳解
    jdk動態代理與靜態代理類對照的是動態代理類,動態代理類的字節碼在程序運行時由Java反射機制動態生成,無需程式設計師手工編寫它的原始碼。動態代理類不僅簡化了編程工作,而且提高了軟體系統的可擴展性,因為Java 反射機制可以生成任意類型的動態代理類。
  • jdk動態代理為什麼要使用接口,而不是使用繼承
    最近面試當時問到了Spring AOP的實現方式,然後就問到了jdk動態代理為什麼使用接口而不是使用繼承,當時一時沒轉過彎來,後來自己回來看了一下原來如此,面試有時就是這樣問題不難,但就是可能想不到這個點去回答。
  • 吃透Java之代理模式
    Java中的代理按照代理類生成時機不同又分為靜態代理和動態代理。靜態代理代理類在編譯期就生成,而動態代理代理類則是在Java運行時動態生成。靜態代理中代理類在編譯期就已經確定,而動態代理則是JVM運行時動態生成,靜態代理的效率相對動態代理來說相對高一些,但是靜態代理代碼冗餘大,一單需要修改接口,代理類和委託類都需要修改。
  • 你知道設計模式中的代理模式嗎?
    代理類和委託類有共同的父類和父接口,這樣在任何使用委託類對象的地方都可以用代理對象代替。代理類負責請求的預處理、過濾、將請求分派給委託類處理、以及委託類執行完請求後的後續處理。,如 dao 層 20 個 dao 類,如果要對方法的訪問權限進行代理,此時需要創建 20 個靜態代理角色,引起類爆炸,無法滿足生產上的需要,於是就催生了動態代理的思想。
  • Spring AOP --JDK動態代理方式
    我們知道Spring是通過JDK或者CGLib實現動態代理的,今天我們討論一下JDK實現動態代理的原理。一、簡述Spring在解析Bean的定義之後會將Bean的定義生成一個BeanDefinition對象並且由BeanDefinitionHolder對象持有。
  • JDK動態代理實現方案
    ProxyFactoryBean是一個實現了FactoryBean的接口,用來生成被被切入的對象。Spring AOP的實現基本上是通過ProxyFactoryBean實現的。我們今天討論的重點也是這個類。我們先看一下一個BeanDefinition轉換成proxyDefintion的過程。
  • 從JVM中dump出動態代理生成的class
    由於動態代理生成的 class 是直接以二進位的方式加載進內存中的,並沒有對應的.class 文件生成,所以如果想通過反編譯工具查看動態代理生成的代碼需要通過特殊的手段來處理。方案一設置運行環境變量,運行後會把 class 文件生成在 classpath 目錄下//動態代理時生成class文件System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","
  • Java 反射以及動態代理,來看就懂了
    動態代理和反射的關係JDK 原生提供的動態代理就是通過反射實現的,但動態代理的實現方式還可以是 ASM(一個短小精悍的字節碼操作框架)、cglib(基於 ASM)等,並不局限於反射。下面我們分別來看:JDK 原生動態代理和 cglib 的實現。
  • 這些JDK 動態代理的面試點你一定要知道
    ,所以在訪問者看來兩者沒有絲毫的區別。通過代理類這中間一層,能有效控制對委託類對象的直接訪問,也可以很好地隱藏和保護委託類對象,同時也為實施不同控制策略預留了空間,從而在設計上獲得了更大的靈活性。Java 動態代理機制以巧妙的方式近乎完美地實踐了代理模式的設計理念。