動態代理系列(二)CGLib動態代理

轉載自:CGLib動態代理的介紹及用法(單回調、多回調、不處理、固定值、懶加載)

本文將介紹下CGLib動態代理及幾種用法。CGLib(Code Generation Library)是一個高效的代碼生成庫,底層實現是使用asm來轉換字節碼生成類。在生成代理類的場景中,由於JDK動態代理必須要求源對象有實現接口,而實際場景中,並不是所有類都有實現接口,因此使用CGLib可以用在未實現接口的類上。

值得注意的幾點是:

  • 使用CGLib代理的類不能是final修飾的,因爲代理類需要繼承主題類;

  • final修飾的方法不會被切入;

  • 如果主題類的構造函數不是默認空參數的,那麼在使用Enhancer類create的時候,選擇create(java.lang.Class[] argumentTypes, java.lang.Object[] arguments) 方法。

接下來認識實現動態代理最重要的一個接口 MethodInteceptor

package net.sf.cglib.proxy;
 
/**
 * General-purpose {@link Enhancer} callback which provides for "around advice".
 * @author Juozas Baliuka <a href="mailto:[email protected]">[email protected]</a>
 * @version $Id: MethodInterceptor.java,v 1.8 2004/06/24 21:15:20 herbyderby Exp $
 */
public interface MethodInterceptor
extends Callback
{
    /**
     * All generated proxied methods call this method instead of the original method.
     * The original method may either be invoked by normal reflection using the Method object,
     * or by using the MethodProxy (faster).
     * @param obj "this", the enhanced object
     * @param method intercepted Method
     * @param args argument array; primitive types are wrapped
     * @param proxy used to invoke super (non-intercepted method); may be called
     * as many times as needed
     * @throws Throwable any exception may be thrown; if so, super method will not be invoked
     * @return any value compatible with the signature of the proxied method. Method returning void will ignore this value.
     * @see MethodProxy
     */    
    public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
                               MethodProxy proxy) throws Throwable;
 
}

MethodInterceptor,從名字上方法攔截器,就是對方法做切入的。intercept方式的4個參數分別對應增強對象、調用方法、方法參數以及調用父類方法的代理。使用MethodProxy速度會更快,所以後面將用

下面介紹幾種用法,這裏使用spring包中cglib,其實和引單獨的cglib包是一樣,只不過spring爲了版本不衝突,將cglib包含在自己的包中。

先定義一個主題對象

public class DBQuery {
 
    public DBQuery() {
    }
 
    public DBQuery(Integer i) {
        System.out.println("Here's in DBQuery Constructor");
    }
 
    public String getElement(String id) {
        return id + "_CGLib";
    }
 
    public List<String> getAllElements() {
        return Arrays.asList("Hello_CGLib1", "Hello_CGLib2");
    }
 
    public String methodForNoop() {
        return "Hello_Noop";
    }
 
    public String methodForFixedValue(String param) {
        return "Hello_" + param;
    }
 
    public final String sayHello() {
        return "Hello Everyone!";
    }

(一)單回調
切入類:

public class DBQueryProxy implements MethodInterceptor {
 
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Here in interceptor !");
        return methodProxy.invokeSuper(o, objects);
    }
}

測試類:

public class TestCGLibProxy {
 
    public static void main(String[] args) {
        DBQueryProxy dbQueryProxy = new DBQueryProxy();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(DBQuery.class);
        enhancer.setCallback(dbQueryProxy);
//        DBQuery dbQuery = (DBQuery)enhancer.create(new Class[]{Integer.class}, new Object[]{1});
        DBQuery dbQuery = (DBQuery) enhancer.create();
        System.out.println(dbQuery.getElement("Hello"));
        System.out.println();
        System.out.println(dbQuery.getAllElements());
        System.out.println();
        System.out.println(dbQuery.sayHello());
    }
}

更多參考:CGLib動態代理的介紹及用法(單回調、多回調、不處理、固定值、懶加載)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章