1. 程式人生 > >JDK動態代理為什麼必須用介面以及與CGLIB的對比

JDK動態代理為什麼必須用介面以及與CGLIB的對比

這兩天對AOP原理感興趣了,試驗了JDK動態代理與CGLIB動態代理。從Spring的AOP框架介紹中得知對於使用介面的類,Spring使用JDK動態代理(原來做專案中試圖從Bean強制轉換為實現類,結果報錯,原來是這麼回事),沒有介面的就使用別的AOP框架aspectj,但這些都是依賴於Java位元組碼工具ASM生成一個原類的新類,呼叫Callback

但是JDK動態代理為什麼必須使用介面一直很疑惑,難道原理不是像ASM一樣修改位元組碼嗎?帶著這個疑問,開始看JDK的Proxy程式碼。使用JDK動態代理的程式碼程式碼

ITestBean tb = (ITestBean) Proxy.newProxyInstance(tb.getClass().getClassLoader(), tb.getClass().getInterfaces(), new TestBeanHander(tb));

於是從建立代理函式看起,即public static Object newProxyInstance(ClassLoader loader,
   Class<?>[] interfaces, InvocationHandler h)
   throws IllegalArgumentException , 

通過原始碼可以看到,這個類第一步生成一個代理類(注意,這裡的引數就是介面列表),

Class cl = getProxyClass(loader, interfaces);

然後通過代理類找到構造引數為InvocationHandler的建構函式並生成一個新類。

Constructor cons = cl.getConstructor(constructorParams);//這個有用,在後面細說
return (Object) cons.newInstance(new Object[] { h });  

介面起什麼作用呢,於是又看getProxyClass方法的程式碼,這個原始碼很長,就不細說了。大致分為三段:

第一:驗證

第二:快取建立新類的結構,如果建立過,則直接返回。(注意:這裡的KEY就是介面列表)

第三:如果沒有建立過,則建立新類

建立程式碼如下

    long num;
   //獲得代理類數字標識 

   synchronized (nextUniqueNumberLock) {
     num = nextUniqueNumber++;
    }

    //獲得建立新類的類名$Proxy,包名為介面包名,但需要注意的是,如果有兩個介面而且不在同一個包下,也會報錯

    String proxyName = proxyPkg + proxyClassNamePrefix + num;
    //呼叫class處理檔案生成類的位元組碼,根據介面列表建立一個新類,這個類為代理類,
    byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
      proxyName, interfaces);
    //通過JNI介面,將Class位元組碼檔案定義一個新類

     proxyClass = defineClass0(loader, proxyName,
       proxyClassFile, 0, proxyClassFile.length);

根據前面的程式碼Constructor cons = cl.getConstructor(constructorParams);

可以猜測到介面建立的新類proxyClassFile 不管採用什麼介面,都是以下結構

public class $Proxy1 extends Proxy implements 傳入的介面{

}
生成新類的看不到原始碼,不過猜測它的執行原理很有可能是如果類是Proxy的子類,則呼叫InvocationHandler進行方法的Invoke

到現在大家都應該明白了吧,JDK動態代理的原理是根據定義好的規則,用傳入的介面建立一個新類,這就是為什麼採用動態代理時為什麼只能用介面引用指向代理,而不能用傳入的類引用執行動態類。

cglib採用的是用建立一個繼承實現類的子類,用asm庫動態修改子類的程式碼來實現的,所以可以用傳入的類引用執行代理類

JDK動態代理與CGLIB對比如下:

//JDK動態代理測試程式碼

ITestBean tb = new TestBean();
tb = (ITestBean) Proxy.newProxyInstance(tb.getClass().getClassLoader(), tb.getClass().getInterfaces(), new TestBeanHander(tb));//這句用介面引用指向,不會報錯

TestBean tmp = (TestBean) tb;//強制轉換為實現類,將丟擲類強制轉換異常

//CGLIB測試程式碼

TestProxy tp = new TestProxy();
tb = (ITestBean) tp.getProxy(TestBean.class);

tmp = (TeatBean) tb;//強制轉換為實現類,不會丟擲異常

補充說明,如果在實現類中,介面定義的方法互相呼叫不會在呼叫InvocationHandler的invoke方法,JDK動態代理應該不是嵌入到Java的反射機制中,而是在反射機制上的一個呼叫

相關推薦

轉:JDK動態代理為什麼必須介面以及CGLIB對比

參考連結: JDK動態代理為什麼必須用介面以及與CGLIB的對比 文章中提到:試驗了JDK動態代理與CGLIB動態代理。從Spring的AOP框架介紹中得知對於使用介面的類,Spring使用JDK動態代理(原來做專案中試圖從Bean強制轉換為實現類,結果報錯,原來是這麼回事),沒有介面的就使用別的

JDK動態代理為什麼必須介面以及CGLIB對比

這兩天對AOP原理感興趣了,試驗了JDK動態代理與CGLIB動態代理。從Spring的AOP框架介紹中得知對於使用介面的類,Spring使用JDK動態代理(原來做專案中試圖從Bean強制轉換為實現類,結果報錯,原來是這麼回事),沒有介面的就使用別的AOP框架aspectj,但

【乾貨】JDK動態代理的實現原理以及如何手寫一個JDK動態代理

動態代理 代理模式是設計模式中非常重要的一種型別,而設計模式又是程式設計中非常重要的知識點,特別是在業務系統的重構中,更是有舉足輕重的地位。代理模式從型別上來說,可以分為靜態代理和動態代理兩種型別。 在解釋動態代理之前我們先理解一下靜態代理: 首先你要明白靜態代理的作用 我們有一

轉:JDK動態代理為什麽必須接口以及CGLIB對比

length exceptio cati class 疑惑 定義 實現類 tails ext 參考鏈接: JDK動態代理為什麽必須用接口以及與CGLIB的對比 文章中提到:試驗了JDK動態代理與CGLIB動態代理。從Spring的AOP框架介紹中得知對於使用接口的類,Spr

JDK動態代理CGLIB動態代理

RR callback arm back 第一個 throw cati proxy clas 一、jdk動態代理 代理目標是 接口實現類的形式 代理的目標對象: 1 public class PersonServiceImpl implements PersonSer

JDK靜態代理JDK動態代理以及CGLIB動態代理

這裡轉載兩篇好文章:“深入理解JDK動態代理機制” ,深入理解CGLIB動態代理機制 : https://www.jianshu.com/p/471c80a7e831 https://www.jianshu.com/p/9a61af393e41?from=timeline&isapp

JDK動態代理CGLib動態代理相關問題

 導讀: 1、JDK動態代理原理是什麼?為什麼不支援類的代理? 2、JDK動態代理例項 3、CGLib代理原理是什麼? 4、CGLib代理例項 5、JDK動態代理與CGLib代理的區別是什麼? 6、總結     注:閱讀本文之前可以先閱讀

JDK動態代理CGLIB 動態代理

一、JDK動態代理 實現方式:通過反射類獲取目標類的介面實現,進行攔截和擴充套件 優點:通過位元組通過反射獲取目標物件的方法進行攔截 缺點:目標物件類一定要實現介面 示例程式碼: public interface UserService { String get

jdk動態代理cglib程式碼實現--SpringAop底層原理

動態代理分為兩類:基於介面的代理和基於繼承的代理 兩類實現的代表是:JDK代理 與 CGlib代理 cglib實現動態代理: 1、定義目標物件: public class RealSubject { //目標物件RealSubject,cglib不

MyBatis實戰之解析執行 MyBatis之反射技術+JDK動態代理+cglib代理 MyBatis之反射技術+JDK動態代理+cglib代理 MyBatis之反射技術+JDK動態代理+cglib代理

本次所談的原理僅僅只涉及基本的框架和核心程式碼,並不會全部都說到,比如關於MyBatis是如何解析XML檔案和其他配置檔案從而的到內容,還有就是JDBC如何使用,關於JDBC如何使用,可以參考我的這篇部落格:單例模式和JDBC 還有就是關於Java基礎方面的內容,個人建議大家抽空看看《Java程式設計思想》

SpringAOP深入瞭解之jdk動態代理CGlib

理解AOP 一般我們編寫程式的思想是縱向的,也就是一個方法程式碼從該方法第一行開始往下一步一步走,直到走完最後一行程式碼。也就是說很多業務都需要的比如使用者鑑權,資源釋放等我們都要在每個方法裡面重複再去呼叫。 public void doMethodOne() {

視覺化說明jdk動態代理cglib動態代理--InvocationHandler--MethodInterceptor

動態代理是為了實現Aop程式設計,代理的是類物件 【jdk動態代理】被代理的類需要實現介面,針對介面的代理,通過生成一個實現了介面的動態類實現代理 ServiceImpl是被代理類,實現介面Servi

jdk動態代理CGLib的區別

jdk動態代理與CGLib的區別 2017年09月20日 22:31:10 E_k_in 閱讀數:5151 動態代理proxy與CGLib的區別 標籤: 代理模式 2013-09-03 08:50 19977人閱讀 評論(4)&nbs

Sping-AOP:cglib動態代理JDK動態代理的區別

預設狀態下,Spring-AOP預設使用JDK動態代理,當需要代理的物件沒有實現任何介面時,才使用cglib動態代理。 下面,將向大家介紹JDK動態代理和Cglib動態代理的使用、兩者的區別已經注意事項。 一、JDK動態代理 由於JDK動態代理是基於介

JDK動態代理CGLIB動態代理應用及原始碼解析

代理模式 代理模式:為其他物件提供一種代理以控制對這個物件的訪問。 代理模式中有三種角色:Subject抽象主題角色、RealSubject真實主題角色、Proxy代理主題角色。Subject描述了業務行為,RealSubject執行具體的業務邏輯,Prox

2.1 Spring宣告式事務的實現方式選擇(JDK動態代理cglib

1、簡介Spring宣告式事務的具體實現方式是動態決定的,與具體配置、以及事務代理物件是否實現介面等有關。2、使用JDK動態代理的情況在滿足下面兩個條件時,Spring會選擇JDK動態代理作為宣告式事務

jdk動態代理示例以及程式碼原理分析

相信很多人在剛剛學習Java時,會感覺【動態代理】晦澀難懂,只知道如何來呼叫它,卻不知道它的實現細節。本文通過根據JDK原始碼,展示這些細節,以期能對JDK的動態代理有深入的理解。 簡單示例程

cglib JDK動態代理的執行效能比較

都說 Cglib 建立的動態代理的執行效能比 JDK 動態代理能高出大概 10 倍,今日抱著懷疑精神驗證了一下,發現情況有所不同,遂貼出實驗結果,以供參考和討論。 程式碼很簡單,首先,定義一個 Test 介面,和一個實現 TestImpl 。Test 介面僅定義一個方法 test,對傳入的 int 引數加

Spring之AOP的實現(JDK動態代理:只能代理介面,不能代理類)

通過動態代理物件,我們可以在動態代理類中加自己想要加的邏輯,而不需要在真實物件的類中新增自己想要的邏輯,提高了程式碼的擴充套件性,降低了耦合性。 java的動態代理機制,缺點:只能代理介面不能代理類。 在學習Spring的時候,我們知道Spring主要有兩大思想,一個

JDK動態代理Dubbo自實現動態代理的研究

1、何為代理?         為了增強目標物件(委託物件)功能,在訪問目標物件的路徑上增加控制訪問物件,該物件負責目標物件執行前後的 附加功能, 該訪問控制物件即為代理物件, 這種設計模式即為代理!