CGLIB是一個強大的高性能的代碼生成包。它被許多AOP的框架(例如Spring AOP)使用,爲他們提供方法的interception(攔截)。Hibernate也使用CGLIB來代理單端single-ended(多對一和一對一)關聯。EasyMock通過使用模仿(moke)對象來測試java代碼的包。它們都通過使用CGLIB來爲那些沒有接口的類創建模仿(moke)對象。
CGLIB包的底層是通過使用一個小而快的字節碼處理框架ASM,來轉換字節碼並生成新的類。不鼓勵直接使用ASM,因爲它要求你必須對JVM內部結構包括class文件的格式和指令集都很熟悉。
下面的圖顯示了和CGLIB包和一些框架和語言的關係。
Spring AOP和Hibernate同時使用JDK的動態代理和CGLIB包。Spring AOP,如果不強制使用CGLIB包,默認情況是使用JDK的動態代理來代理接口。
CGLIB包對代理那些沒有實現接口的類非常有用。它是通過動態的生成一個子類去覆蓋所要代理類的不是final的方法,並設置好callback,則原有類的每個方法調用就會轉變成調用用戶定義的攔截方法(interceptors)。
net.sf.cglib.proxy.Callback接口在CGLIB包中是一個很關鍵的接口,所有被net.sf.cglib.proxy.Enhancer類調用的回調(callback)接口都要繼承這個接口。 用net.sf.cglib.proxy.MethodInterceptor接口是最通用的回調(callback)類型,它經常被基於代理的AOP用來實現攔截(intercept)方法的調用。
net.sf.cglib.proxy.MethodInterceptor能夠滿足任何的攔截(interception )需要,但是某些特殊情況下可能使用過度。爲了簡化和提高性能,CGLIB包提供了一些專門的回調(callback)類型。例如:
net.sf.cglib.proxy.FixedValue 爲提高性能,FixedValue回調對強制某一特別方法返回固定值是有用的。
net.sf.cglib.proxy.NoOp NoOp回調把對方法調用直接委派到這個方法在父類中的實現。
net.sf.cglib.proxy.LazyLoader 當實際的對象需要延遲裝載時,可以使用LazyLoader回調。一旦實際對象被裝載,它將被每一個調用代理對象的方法使用。
net.sf.cglib.proxy.Dispatcher 和LazyLoader不同的是,當代理方法被調用時,裝載對象的方法也總要被調用。
net.sf.cglib.proxy.ProxyRefDispatcher 和Dispatcher不同的是,它可以把代理對象作爲裝載對象方法的一個參數傳遞。
爲了更好的使用代理,我們可以使用自己定義的MethodInterceptor類型回調(callback)來代替net.sf.cglib.proxy.NoOp回調。當對代理中所有方法的調用時,都會轉向MethodInterceptor類型的攔截(intercept)方法,在攔截方法中再調用底層對象相應的方法。
例一:
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
}
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.MethodInterceptor;
public class Test {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyClass.class);
enhancer.setCallback( new MethodInterceptorImpl() );
MyClass my = (MyClass)enhancer.create();
my.method();
}
private static class MethodInterceptorImpl implements MethodInterceptor {
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println(method);
proxy.invokeSuper(obj, args);
return null;
}
}
}
/*
javac -cp .;cglib-2.1.3.jar;asm-1.5.3.jar *.java
pause
java -cp .;cglib-2.1.3.jar;asm-1.5.3.jar Test
pause
*/