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

 導讀:java

一、JDK動態代理原理是什麼?爲何不支持類的代理?spring

二、JDK動態代理實例數組

三、CGLib代理原理是什麼?框架

四、CGLib代理實例ide

五、JDK動態代理與CGLib代理的區別是什麼?性能

六、總結測試

 

 

注:閱讀本文以前能夠先閱讀:什麼是代理模式? 優化

 

1. JDK動態代理原理是什麼?爲何不支持類的代理?this

 jdk動態代理圖:spa

 

利用攔截器(攔截器必須實現InvocationHanlder)加上反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。是在程序運行的過程當中,根據被代理的接口來動態生成代理類的class文件,並加載運行的過程。

之因此只支持實現了接口的類的代理。從原理上講是由於JVM動態生成的代理類有以下特性:

繼承了Proxy類,實現了代理的接口,最終形式以下(HelloInterface爲被代理類實現的接口):

 

public final class $Proxy0 extends Proxy implements HelloInterface{ ....... }

然而因爲java不能多繼承,這裏已經繼承了Proxy類了,不能再繼承其餘的類,因此JDK的動態代理不支持對實現類的代理,只支持接口的代理。

 從使用上講,建立代理類時必須傳入被代理類實現的接口。

 

1.1 詳細介紹:

java的動態代理機制中,有兩個重要的類或接口,一個是 InvocationHandler(Interface)、另外一個則是 Proxy(Class),這一個類和接口是實現咱們動態代理所必須用到的。

1.1.1 InvocationHandler

每個動態代理類都必需要實現InvocationHandler這個接口,而且每一個代理類的實例都關聯了一個handler,當咱們經過代理對象調用一個方法的時候,這個方法的調用就會被轉發爲由InvocationHandler這個接口的 invoke 方法來進行調用。

InvocationHandler這個接口的惟一一個方法 invoke 方法:

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

這個方法一共接受三個參數,那麼這三個參數分別表明以下: 

  • proxy:  指代JDK動態生成的最終代理對象
  • method: 指代的是咱們所要調用真實對象的某個方法的Method對象
  • args:   指代的是調用真實對象某個方法時接受的參數

1.1.2 Proxy

Proxy這個類的做用就是用來動態建立一個代理對象的類,它提供了許多的方法,可是咱們用的最多的就是 newProxyInstance 這個方法:

 

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) throws IllegalArgumentException

 

這個方法的做用就是獲得一個動態的代理對象,其接收三個參數,咱們來看看這三個參數所表明的含義: 

  • loader:  ClassLoader對象,定義了由哪一個ClassLoader來對生成的代理對象進行加載。
  • interfaces:  Interface對象的數組,表示的是我將要給我須要代理的對象提供一組什麼接口,若是我提供了一組接口給它,那麼這個代理對象就宣稱實現了該接口(多態),這樣我就能調用這組接口中的方法了。
  • HandlerInvocationHandler對象,表示的是當我這個動態代理對象在調用方法的時候,會關聯到哪個InvocationHandler對象上。

因此咱們所說的DynamicProxy(動態代理類)是這樣一種class:它是在運行時生成的class,在生成它時你必須提供一組interface給它,而後該class就宣稱它實現了這些 interface。這個DynamicProxy其實就是一個Proxy,它不會作實質性的工做,在生成它的實例時你必須提供一個handler,由它接管實際的工做。

 

2. JDK動態代理實例

2.1 建立接口類

public interface HelloInterface { void sayHello(); }

 

2.2 建立被代理類,實現接口 

/** * 被代理類 */

public class HelloImpl implements HelloInterface{ @Override public void sayHello() { System.out.println("hello"); } }


2.3
建立InvocationHandler實現類 

 

/** * 每次生成動態代理類對象時都須要指定一個實現了InvocationHandler接口的調用處理器對象 */

public class ProxyHandler implements InvocationHandler{ private Object subject; // 這個就是咱們要代理的真實對象,也就是真正執行業務邏輯的類

    public ProxyHandler(Object subject) {// 經過構造方法傳入這個被代理對象

        this.subject = subject; } /** *當代理對象調用真實對象的方法時,其會自動的跳轉到代理對象關聯的handler對象的invoke方法來進行調用 */ @Override public Object invoke(Object obj, Method method, Object[] objs) throws Throwable { Object result = null; System.out.println("能夠在調用實際方法前作一些事情"); System.out.println("當前調用的方法是" + method.getName()); result = method.invoke(subject, objs);// 須要指定被代理對象和傳入參數
 System.out.println(method.getName() + "方法的返回值是" + result); System.out.println("能夠在調用實際方法後作一些事情"); System.out.println("------------------------"); return result;// 返回method方法執行後的返回值
 } }

 

 

 

2.4 測試 

public class Mytest { public static void main(String[] args) { //第一步:建立被代理對象
 HelloImpl hello = new HelloImpl(); //第二步:建立handler,傳入真實對象
 ProxyHandler handler = new ProxyHandler(hello); //第三步:建立代理對象,傳入類加載器、接口、handler
 HelloInterface helloProxy = (HelloInterface) Proxy.newProxyInstance( HelloInterface.class.getClassLoader(), new Class[]{HelloInterface.class}, handler); //第四步:調用方法
 helloProxy.sayHello(); } }


2.5 結果
 

能夠在調用實際方法前作一些事情 當前調用的方法是sayHello hello sayHello方法的返回值是null 能夠在調用實際方法後作一些事情 ------------------------

 

3. CGLib代理原理是什麼?

 

CGLib採用了很是底層的字節碼技術,其原理是經過字節碼技術爲一個類建立子類,並在子類中採用方法攔截的技術攔截全部父類方法的調用,順勢織入橫切邏輯。(利用ASM開源包,對代理對象類的class文件加載進來,經過修改其字節碼生成子類來處理)

3.1 CGLib核心類:

一、 net.sf.cglib.proxy.Enhancer主要加強類,經過字節碼技術動態建立委託類的子類實例;

Enhancer多是CGLIB中最經常使用的一個類,和Java1.3動態代理中引入的Proxy類差很少。和Proxy不一樣的是,Enhancer既可以代理普通的class,也可以代理接口。Enhancer建立一個被代理對象的子類而且攔截全部的方法調用(包括從Object中繼承的toStringhashCode方法)。Enhancer不可以攔截final方法,例如Object.getClass()方法,這是因爲Java final方法語義決定的。基於一樣的道理,Enhancer也不能對fianl類進行代理操做。這也是Hibernate爲何不能持久化final class的緣由。

2net.sf.cglib.proxy.MethodInterceptor經常使用的方法攔截器接口,須要實現intercept方法,實現具體攔截處理;

public java.lang.Object intercept(java.lang.Object obj, java.lang.reflect.Method method, java.lang.Object[] args, MethodProxy proxy) throws java.lang.Throwable{}
  • obj:動態生成的代理對象 
  • method : 實際調用的方法
  • args:調用方法入參
  • proxy
  • net.sf.cglib.proxy.MethodProxyjava Method類的代理類,能夠實現委託類對象的方法的調用;經常使用方法:methodProxy.invokeSuper(proxy, args);在攔截方法內能夠調用屢次

 

4. CGLib代理實例

4.1 建立被代理類

public class SayHello { public void say(){ System.out.println("hello"); } }

 

4.2 建立代理類 

/** *代理類 */

public class ProxyCglib implements MethodInterceptor{ private Enhancer enhancer = new Enhancer(); public Object getProxy(Class clazz){ //設置須要建立子類的類 
 enhancer.setSuperclass(clazz); enhancer.setCallback(this); //經過字節碼技術動態建立子類實例 

  return enhancer.create(); } //實現MethodInterceptor接口方法 

 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("能夠在調用實際方法前作一些事情"); //經過代理類調用父類中的方法 
 Object result = proxy.invokeSuper(obj, args); System.out.println("能夠在調用實際方法後作一些事情"); return result; } }

 

4.3 測試 

public class Mytest { public static void main(String[] args) { ProxyCglib proxy = new ProxyCglib(); //經過生成子類的方式建立代理類 
 SayHello proxyImp = (SayHello)proxy.getProxy(SayHello.class); proxyImp.say(); } }

 

4.4 結果 

能夠在調用實際方法前作一些事情 hello 能夠在調用實際方法後作一些事情

 

5. JDK動態代理與CGLib代理的區別是什麼?

5.1 原理區別:

java動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。核心是實現InvocationHandler接口,使用invoke()方法進行面向切面的處理,調用相應的通知。

cglib動態代理是利用asm開源包,對代理對象類的class文件加載進來,經過修改其字節碼生成子類來處理。核心是實現MethodInterceptor接口,使用intercept()方法進行面向切面的處理,調用相應的通知。

1、若是目標對象實現了接口,默認狀況下會採用JDK的動態代理實現AOP

2、若是目標對象實現了接口,能夠強制使用CGLIB實現AOP

3、若是目標對象沒有實現了接口,必須採用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換

 

5.2 性能區別:

1CGLib底層採用ASM字節碼生成框架,使用字節碼技術生成代理類,在jdk6以前比使用Java反射效率要高。惟一須要注意的是,CGLib不能對聲明爲final的方法進行代理,由於CGLib原理是動態生成被代理類的子類。

2、在jdk6jdk7jdk8逐步對JDK動態代理優化以後,在調用次數較少的狀況下,JDK代理效率高於CGLIB代理效率,只有當進行大量調用的時候,jdk6jdk7CGLIB代理效率低一點,可是到jdk8的時候,jdk代理效率高於CGLIB代理。

 

5.3 各自侷限:

1JDK的動態代理機制只能代理實現了接口的類,而不能實現接口的類就不能實現JDK的動態代理。

2cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現加強,但由於採用的是繼承,因此不能對final修飾的類進行代理。

 

6. 總結

 

 

擴展閱讀:動態代理是基於什麼原理?

相關文章
相關標籤/搜索