JDK動態代理與Cglib動態代理(轉載)

spring容器經過動態代理再結合java反射思想能夠使得方法調用更加簡潔java

1、動態代理概述:

    與靜態代理對照(關於靜態代理的介紹 能夠閱讀上一篇:JAVA設計模式之 代理模式【Proxy Pattern】(博主),spring

    動態代理類的字節碼是在程序運行時由Java反射機制動態生成。設計模式

    注意: 
      一、AspectJ是採用編譯時生成AOP代理類,具備更好的性能,可是須要使用特定的編譯器進行處理
框架

      二、Spring AOP採用運行時生成AOP代理類,無需使用特定編譯器進行處理,可是性能相對於AspectJ較差eclipse

2、JDK動態代理 [對有實現接口的對象作代理]

    一、JDK動態代理中 須要瞭解的兩個重要的類或接口 [InvocationHandler 和 Proxy]
ide

         ① InvocationHandler接口函數

public interface InvocationHandler {   
    public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;   
}

參數說明: 
Object proxy:指被代理的對象 
Method method:咱們所要調用被代理對象的某個方法的Method對象
Object[] args:被代理對象某個方法調用時所須要的參數 

能夠將InvocationHandler接口的子類想象成一個代理的最終操做類。
性能

說明:每個動態代理類都必需要實現InvocationHandler這個接口,而且每一個代理類(Proxy)的實例都關聯到了一個handler,當咱們經過代理對象調用一個方法的時候,這個方法的調用就會被轉發爲由InvocationHandler這個接口的 invoke 方法來進行調用。同時在invoke的方法裏 咱們能夠對被代理對象的方法調用作加強處理(如添加事務、日誌、權限驗證等操做)。測試

         ② Proxy類this

 Proxy類是專門完成代理的操做類,能夠經過此類爲一個或多個接口動態地生成實現類,該類經常使用的調用方法以下:

 

newProxyInstance方法參數說明以下:

ClassLoader loader:類加載器,定義了由哪一個ClassLoader對象來對生成的代理對象進行加載
Class<?>[] interfaces:獲得被代理類所有的接口,若是我提供了一組接口給它,那麼這個代理對象就宣稱實現了該接口,這樣我就能調用這組接口中的方法了
InvocationHandler h:獲得InvocationHandler接口的子類實例 


    二、JDK動態代理代碼示例:

首先咱們定義了一個Subject類型的接口:Subject.java

public interface Subject {  
    public void visit();  
}

接着定義一個接口的實現類,這個類就是咱們示例中的被代理對象:RealSubject.java

/** 
 * 被代理類 
 * @author lvzb.software@qq.com 
 * 
 */  
public class RealSubject implements Subject {  
  
    @Override  
    public void visit() {  
         System.out.println("I am 'RealSubject',I am the execution method");  
    }  
  
}

第三步 定義一個動態代理類(必需要實現 InvocationHandler 這個接口):DynamicProxy.java

import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
/** 
 * JDK動態代理類 
 * @author lvzb.software@qq.com 
 * 
 */  
public class DynamicProxy implements InvocationHandler {  
  
    // 咱們要代理的真實對象(委託對象)  
    private Object subject;  
      
    // 構造方法,給咱們要代理的真實對象賦初值  
    public DynamicProxy(Object obj){  
        this.subject = obj;  
    }  
      
    @Override  
    public Object invoke(Object object, Method method, Object[] args)  
            throws Throwable {  
        // 在代理真實對象操做前 咱們能夠添加一些本身的操做  
        System.out.println("before proxy invoke");  
          
        // 當代理對象調用真實對象的方法時,其會自動的跳轉到代理對象關聯的handler對象的invoke方法來進行調用  
        method.invoke(subject, args);  
          
        // 在代理真實對象操做後 咱們也能夠添加一些本身的操做  
        System.out.println("after proxy invoke");  
        return null;  
    }  
  
}


最後代理測試類:Client.java

import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Proxy;  
  
public class Client {  
  
    public static void main(String[] args) {  
        // 咱們要代理的真實對象  
        Subject realSubject = new RealSubject();  
        // 咱們要代理哪一個真實對象,就將該對象傳進去,最後是經過該真實對象調用方法的  
        InvocationHandler handler = new DynamicProxy(realSubject);  
        /* 
         * 經過Proxy的newProxyInstance方法來動態建立咱們的代理對象,咱們來看看其三個參數< 
         * 參數一:咱們這裏使用handler這個類的ClassLoader對象來加載咱們的代理對象 
         * 參數二:咱們這裏爲代理對象提供的接口是真實對象所實行的接口,表示我要代理的是該真實對象,這樣我就能調用這組接口中的方法了 
         * 參數三:咱們這裏將這個代理對象關聯到了上方的 InvocationHandler 這個對象上 
         */  
        Subject proxyInstance = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(),   
                RealSubject.class.getInterfaces(),   
                handler);  
          
        System.out.println(proxyInstance.getClass().getName());  
        proxyInstance.visit();  
  
    }  
  
}


運行->控制檯輸出結果以下:

com.sun.proxy.$Proxy0  
before proxy invoke  
I am 'RealSubject',I am the execution method  
after proxy invoke


3、Cglib(Code Generation Library)動態代理 [對沒有實現接口的普通類作代理]

     一、概述:

         Cglib是一個優秀的動態代理框架,它的底層使用ASMJAVA字節碼處理框架在內存中動態的生成被代理類的子類。使用CGLIB即便被代理類沒有實現任何接 也能夠實現動態代理功能。可是不能對final修飾的類進行代理。

     二、原理:

         經過字節碼技術爲一個類建立子類,並在子類中採用方法攔截的技術攔截全部父類方法的調用。

         <JDK動態代理與CGLib動態代理均是實現Spring AOP的基礎>

     三、使用:

          使用Cglib前須要導入如下兩個jar文件:
          asm.jar – Cglib的底層實現。

        【cglib包的底層是使用字節碼處理框架ASM來轉換字節碼並生成新的類,因此cglib包要依賴於asm包】
          cglib.jar - Cglib的核心jar包。


     四、Cglib動態代理代碼示例:

首先定義一個沒有實現接口的代理委託類:CglibRealSubject.java

/** 
 * 沒有實現接口的代理委託類 
 * @author lvzb.software@qq.com 
 * 
 */  
public class CglibRealSubject{  
  
    public void visit() {  
        System.out.println("I am 'RealSubject',I am the execution method");  
    }  
  
}


接着定義一個Cglib動態代理類: CglibDynamicProxy.java

import java.lang.reflect.Method;  
  
import net.sf.cglib.proxy.Enhancer;  
import net.sf.cglib.proxy.MethodInterceptor;  
import net.sf.cglib.proxy.MethodProxy;  
/** 
 * 使用cglib動態代理 
 * @author lvzb.software@qq.com 
 * 
 */  
public class CglibDynamicProxy implements MethodInterceptor {  
  
    private Object target;  
      
    /** 
     * 建立代理對象 
     * @param target 被代理的對象 
     * @return 
     */  
    public Object getProxyInstance(Object target){  
        this.target = target;  
        // 聲明加強類實例  
        Enhancer enhancer = new Enhancer();   
        // 設置被代理類字節碼,CGLIB根據字節碼生成被代理類的子類  
                enhancer.setSuperclass(this.target.getClass());    
                // 設置要代理的攔截器,回調函數,即一個方法攔截   new MethodInterceptor()  
                enhancer.setCallback(this);   
                // 建立代理對象 實例   
                return enhancer.create();    
    }  
      
    @Override  
    public Object intercept(Object obj, Method method, Object[] args,  
            MethodProxy proxy) throws Throwable {  
        // 在代理真實對象操做前 咱們能夠添加一些本身的操做  
        System.out.println("前置代理,加強處理");  
          
        proxy.invokeSuper(obj, args);  
          
        // 在代理真實對象操做後 咱們也能夠添加一些本身的操做  
        System.out.println("後置代理,加強處理");  
        return null;  
    }  
  
}

最後測試客戶端類:CglibClient.java

public class CglibClient {  
  
    public static void main(String[] args) {  
        CglibDynamicProxy cglib = new CglibDynamicProxy();  
        CglibRealSubject realSubject = (CglibRealSubject) cglib.getProxyInstance(new CglibRealSubject());  
        realSubject.visit();  
    }  
  
}


運行->控制檯輸出結果以下:

前置代理,加強處理  
I am 'RealSubject',I am the execution method  
後置代理,加強處理
相關文章
相關標籤/搜索