Java動態代理模式jdk和cglib

jdk動態代理實例

jdk動態代理模式裏面有個攔截器的概念,在jdk中,只要實現了InvocationHandler接口的類就是一個攔截器類
還使用了些反射的相關概念。
攔截器的概念不瞭解沒關係,假如寫了個請求到action,經過攔截器,然後纔會到action。然後繼續有之後的操作。
攔截器就像一個過濾網,一層層的過濾,只要滿足一定條件,才能繼續向後執行。
攔截器的作用:控制目標對象的目標方法的執行。

攔截器的具體操作步驟:
1.引入類:目標類和一些擴展方法相關的類。
2.賦值:調用構造函數給相關對象賦值
3.合併邏輯處理:在invoke方法中把所有的邏輯結合在一起。最終決定目標方法是否被調用。

下面看具體的代碼實例:

目標接口類:
package com.sss.designPattern.proxy.dynamicProxy.jdkDynamicProxy;  
  
/** 
 * 目標接口: 
 * 包含目標方法的聲明 
 */  
public interface TargetInterface {  
    /** 
     * 目標方法 
     */  
    void business();  
}  

目標類:
package com.sss.designPattern.proxy.dynamicProxy.jdkDynamicProxy;  
  /** 
 * 被代理的類 
 * 目標對象類 
 * 實現目標接口. 
 * 繼而實現目標方法。 
 */  
public class TargetObject implements TargetInterface {  
  
    /** 
     * 目標方法(即目標操作) 
     */  
    @Override  
    public void business() {  
        System.out.println("business");  
    }  
  
}  

攔截器:
package com.sss.designPattern.proxy.dynamicProxy.jdkDynamicProxy;  
  
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
  
/** 
 * 動態代理-攔截器 
 */  
public class MyInterceptor implements InvocationHandler {  
    private Object target;//目標類  
  
    public MyInterceptor(Object target) {  
        this.target = target;  
    }  
  
    /** 
     * args 目標方法的參數 
     * method 目標方法 
     */  
    @Override  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
        System.out.println("aaaaa");//切面方法a();  
        //。。。  
        method.invoke(this.target, args);//調用目標類的目標方法  
        //。。。  
        System.out.println("bbbbb");//切面方法f();  
        return null;  
    }  
}  

具體通過調用代理對象,來調用目標對象的目標方法的具體測試:
[java] view plain copy
package com.sss.designPattern.proxy.dynamicProxy.jdkDynamicProxy;  
  
import java.lang.reflect.Proxy;  
  
public class MainTest {  
    public static void main(String[] args) {  
        //目標對象  
        TargetObject target = new TargetObject();  
        //攔截器  
        MyInterceptor myInterceptor = new MyInterceptor(target);  
  
        /* 
         *  Proxy.newProxyInstance參數: 
         *  1、目標類的類加載器 
         *  2、目標類的所有的接口 
         *  3、攔截器 
         */  
        //代理對象,調用系統方法自動生成  
        TargetInterface proxyObj = (TargetInterface) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), myInterceptor);  
        proxyObj.business();  
    }  
}  

看完代碼實例,要對這個動態代理進一步理解,要考慮到以下的問題。
1、代理對象是由誰產生的?

JVM,不像上次的靜態代理,我們自己得new個代理對象出來。
2、代理對象實現了什麼接口?
實現的接口是目標對象實現的接口。
同靜態代理中代理對象實現的接口。那個繼承關係圖還是相同的。
代理對象和目標對象都實現一個共同的接口。就是這個接口。
所以Proxy.newProxyInstance()方法返回的類型就是這個接口類型。
3、代理對象的方法體是什麼?
代理對象的方法體中的內容就是攔截器中invoke方法中的內容。所有代理對象的處理邏輯,控制是否執行目標對象的目標方法。都是在這個方法裏面處理的。
4、攔截器中的invoke方法中的method參數是在什麼時候賦值的?
在客戶端,代理對象調用目標方法的時候,此實例中爲:proxyObj.business();實際上進入的是攔截器中的invoke方法,這個時候
,攔截器中的invoke方法中的method參數會被賦值。

最後,爲啥這個方式叫做jdk動態代理呢?
因爲這個動態代理對象是用jdk的相關代碼生成的,所以這個叫jdk動態代理
後面的cglib動態代理,就是因爲要用到cglib的jar包,所以才叫cglib動態代理

瞭解了一個,那麼另一個也就差不多啦。就繼續往下看吧。

爲什麼要使用這個cglib來實現這個動態代理呢?因爲spring框架要用。

具體的代碼實現如下:

目標對象類:
package com.sss.designPattern.proxy.dynamicProxy.cglbDynamicProxy;  
  
/** 
 * 被代理的類 
 * 目標對象類 
 */  
public class TargetObject {  
  
    /** 
     * 目標方法(即目標操作) 
     */  
    public void business() {  
        System.out.println("business");  
    }  
  
}  

攔截器類:
package com.sss.designPattern.proxy.dynamicProxy.cglbDynamicProxy;  
  
import net.sf.cglib.proxy.Enhancer;  
import net.sf.cglib.proxy.MethodInterceptor;  
import net.sf.cglib.proxy.MethodProxy;  
  
import java.lang.reflect.Method;  
  
/** 
 * 動態代理-攔截器 
 */  
public class MyInterceptor implements MethodInterceptor {  
    private Object target;//目標類  
  
    public MyInterceptor(Object target) {  
        this.target = target;  
    }  
  
    /** 
     * 返回代理對象 
     * 具體實現,暫時先不追究。 
     */  
    public Object createProxy() {  
        Enhancer enhancer = new Enhancer();  
        enhancer.setCallback(this);//回調函數  攔截器  
        //設置代理對象的父類,可以看到代理對象是目標對象的子類。所以這個接口類就可以省略了。  
        enhancer.setSuperclass(this.target.getClass());  
        return enhancer.create();  
    }  
  
    /** 
     * args 目標方法的參數 
     * method 目標方法 
     */  
    @Override  
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {  
        System.out.println("aaaaa");//切面方法a();  
        //。。。  
        method.invoke(this.target, objects);//調用目標類的目標方法  
        //。。。  
        System.out.println("bbbbb");//切面方法f();  
        return null;  
    }  
}  

測試類:
[java] view plain copy
package com.sss.designPattern.proxy.dynamicProxy.cglbDynamicProxy;  
  
public class MainTest {  
    public static void main(String[] args) {  
        //目標對象  
        TargetObject target = new TargetObject();  
        //攔截器  
        MyInterceptor myInterceptor = new MyInterceptor(target);  
        //代理對象,調用cglib系統方法自動生成  
        //注意:代理類是目標類的子類。  
        TargetObject proxyObj = (TargetObject) myInterceptor.createProxy();  
        proxyObj.business();  
    }  
}  

區別:
首先從文件數上來說,cglib比jdk實現的少了個接口類。因爲cglib返回的代理對象是目標對象的子類。而jdk產生的代理對象和目標對象都實現了一個公共接口。


動態代理分爲兩種:

  • jdk的動態代理

    • 代理對象和目標對象實現了共同的接口
    • 攔截器必須實現InvocationHanlder接口
  • cglib的動態代理

    • 代理對象是目標對象的子類
    • 攔截器必須實現MethodInterceptor接口
    • hibernate中session.load採用的是cglib實現的
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章