cglib入門
代理為要控制訪問的類提供了一種可行的途徑,他為目標類引入一個中間層,JDK1.3后也有動態代理,不過性能不是很好,1.6有所加強。CGLIB是一個強大的代碼生成包,在ASM上建立,在一些開源工具中經常可以看到他的身影,比如hibernate,spring。
CGLIB底層通過字節碼處理框架ASM來將字節碼生成新的類,在spring AOP中不強制使用CGLIB,默認是JDK動態代理。
CGLIB 包情況:
net.sf.cglib.core:底層字節碼處理類,大部分與ASM有關。
net.sf.cglib.transform:編譯期或運行期和類文件的轉換
net.sf.cglib.proxy:實現創建代理和方法攔截器的類
net.sf.cglib.reflect:實現快速放射
net.sf.cglib.util:工具包
net.sf.cglib.beans:javabean相關工具類
通過CGLIB創建動態代理,本質上,他是動態的生成目標類的子類,覆蓋目標類所有不是final的方法,并給他們設置好callback,因此,原有類的每個方法調用就會變成自定義的攔截方法。
創建動態代理時通常要用到如下api:net.sf.cglib.proxy.Callback這個接口,他是很關鍵的一個接口,所有被net.sf.cglib.proxy.Enhancer類調用的回調借口都要繼承這個接口
如: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;
}
這個是基與方法的回調,第一個參數是代理對象,第二個是被攔截的方法對象,第三個是方法參數,第四個是方法的代理對象。
public class MyClass {
public void method1() {
System.out.println("method1");
}
public void method2() {
System.out.println("method2");
}
}
攔截器:
public class MethodInterceptImpl implements MethodInterceptor {
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
System.out.println(arg1.getName()+"--intercept");
arg3.invokeSuper(arg0, arg2);// 這里其實也可以用原來的方法對象來執行,但是性能上不如cglib的方法代理類
return null;
}
public class MainTest {
public static void main(String[] args) {
simpleTest();
}
private static void simpleTest() {
Enhancer en = new Enhancer();
en.setCallback(new MethodInterceptImpl());
en.setSuperclass(MyClass.class);
MyClass m = (MyClass) en.create();
m.method1();
m.method2();
}
結果:method1--intercept
method1
method2--intercept
method2
現實項目中可能存在某些需求,比如method1需要攔截,而method2不需要攔截。那我們可以對callback做下選擇,使用net.sf.cglib.proxy.CallbackFilter做一些過濾。
public class MethodFilterImpl implements CallbackFilter {
private final static int execute = 0;
private final static int unexecute = 1;
public int accept(Method method) {
String methodName = method.getName();
if("method1".equals(methodName)){
return execute;
}
return unexecute;
}
}
調用的時候需要給callback設置好索引位置,因為accept的返回值就是callbacks數組的索引位置。
private static void filterTest() {
Enhancer en = new Enhancer();
Callback[] callbacks = new Callback[] { new MethodInterceptImpl(),
NoOp.INSTANCE };//這里攔截器的索引位置要與filter里的設置一致
en.setCallbacks(callbacks);
en.setSuperclass(MyClass.class);
en.setCallbackFilter(new MethodFilterImpl());
MyClass m = (MyClass) en.create();
m.method1();
m.method2();
}
這里callbacks[1]這個位置使用了NoOp這個回調接口
public interface NoOp extends Callback
{
/**
* A thread-safe singleton instance of the <code>NoOp</code> callback.
*/
public static final NoOp INSTANCE = new NoOp() { };
}
這個callback其實就是直接把任務委派給這個方法在父類中的實現,其實也等同于沒做什么額外的事情
執行結果:method1--intercept
method1
method2
method2 并未被MethodInterceptImpl攔截
}
posted on 2010-10-26 14:27 羔羊 閱讀(1042) 評論(1) 編輯 收藏 所屬分類: aop