總的來講,不管是cglib、jdk動態代理又或者是aop面向切面編程,都運用到了一個最重要的設計模式--代理模式!萬變不離其終,學好代理模式,打遍天下無敵手!java
cglib就是一個字節碼生成
和轉換
的庫嘛!這卻是不難理解,它主要被AOP,測試,數據訪問框架用來生成動態代理對象
和攔截字段訪問
。編程
今天咱們就來講說cglib在代理方面的應用!設計模式
首先咱們來看看cglib源碼的包結構:數組
從cglib核心包中能夠看到有個proxy
的包,咱們一塊兒去探個究竟!展開proxy
能夠發現:bash
在該包中的Enhancer
類和MethodInterceptor
接口是整個包的核心所在!Enhancer
就是「加強」的意思嘛!主要用於生成動態子類
以啓用方法攔截,什麼意思?這樣子講!cglib類代理的基本思想就是對被代理類生成一個新的類(proxy
),該類是繼承自被代理類的,並對被代理類方法執行先後執行一些操做,這些操做的一般就是一些回調操做,能夠是MethodInterceptor
,LazyLoader
,CallbackFilter
,其中MethodInterceptor
是最經常使用的。框架
全部被Enhancer
關聯的對象默認都是實現Factory
接口的,該接口提供了一組能夠設置對象回調類型的方法,你能夠經過調用setUseFactory(false)
取消此特性!ide
須要注意的是,cglib是沒法代理final
修飾的方法的,由於這是java語言規範決定的!測試
MethodInterceptor
是一個提供環繞通知
的通用回調接口!Aop中有這樣的術語,那就是前置通知
,後置通知
,環繞通知
,很是好理解,就是一個在方法執行前的通知,一個方法執行後的通知,另一個就是方法執行先後都通知。ui
該接口只有一個intercept()
方法:spa
public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
MethodProxy proxy) throws Throwable;
複製代碼
全部對被代理類方法的執行都會跳轉到這個方法上面來,而原來的方法則經過反射獲得的Method
對象或者MethodProxy
對象進行調用。
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
class Student {
private String name = "zhangsan";
public String getStuName() {
return name;
}
}
public class CglibMethodInterceptTest {
public static void main(String[] args) {
//建立一個Enhancer對象
Enhancer enchaner = new Enhancer();
//設置被代理的類
enchaner.setSuperclass(Student.class);
//建立一個回調接口
Callback interceptor = new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable {
System.err.println("原方法名是 : " + method.getName());
System.err.println("原方法聲明的類爲 " + method.getDeclaringClass());
System.err.println("我是 " + (String) proxy.invokeSuper(obj, args));
System.err.println("我調用結束了");
return null;
}
};
enchaner.setCallback(interceptor);
Student student = (Student) enchaner.create();
student.getStuName();
}
}
複製代碼
輸出的結果爲:
原方法名是 : getStuName
原方法聲明的類爲 class wokao666.test.Student
我是 zhangsan
我調用結束了
複製代碼
過濾器的使用
package wokao666.test;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.NoOp;
class Student {
private String name = "zhangsan";
private String rename = "rename";
public String getStuName() {
return name;
}
public String getRename() {
return rename;
}
}
public class CglibMethodInterceptTest {
public static void main(String[] args) {
//建立一個Enhancer對象
Enhancer enchaner = new Enhancer();
//設置被代理的類
enchaner.setSuperclass(Student.class);
//建立一個回調接口
Callback interceptor = new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable {
System.err.println("原方法名是 : " + method.getName());
System.err.println("原方法聲明的類爲 " + method.getDeclaringClass());
System.err.println("我是 " + (String) proxy.invokeSuper(obj, args));
System.err.println("我調用結束了");
return proxy.invokeSuper(obj, args);
}
};
CallbackFilter callbackFilter = new CallbackFilter() {
@Override
public int accept(Method method) {
int flag = 0;
if ("getStuName".equals(method.getName())) {
System.err.println("我將此方法過濾掉了,不對該方法進行攔截");
return 1;
}
return 0;
}
};
Callback[] callbacks = new Callback[] { interceptor, NoOp.INSTANCE };
enchaner.setCallbackFilter(callbackFilter);
enchaner.setCallbacks(callbacks);
Student student = (Student) enchaner.create();
System.err.println(student.getStuName());
System.err.println(student.getRename());
}
}
複製代碼
我將此方法過濾掉了,不對該方法進行攔截
zhangsan
原方法名是 : getRename
原方法聲明的類爲 class wokao666.test.Student
我是 rename
我調用結束了
rename
複製代碼
NoOp.INSTANCE
:這個NoOp
表示no operator
,即什麼操做也不作,代理類直接調用被代理的方法不進行攔截。
getStuName
對應的CallbackFilter中定義的索引1,在Callback[]
數組中使用的過濾爲NoOp
,所以直接執行了被代理方法。
getRename
對應CallbackFilter中定義的索引0,在Callback[]
數組中使用的過濾爲interceptor
,所以執行了方法攔截器進行攔截。
我寫的只是一點皮毛,建議你們在此基礎上多動手,結合源代碼多寫寫一些例子,寫多了,懂得就多了!