概述
和JDK動態代理的思想一樣,Cglib也爲方法調用提供了回調。Cglib提供了多個回調接口,它們都繼承了一個net.sf.cglib.proxy.Callback的marker接口。Cglib爲Callback接口提供瞭如下7個子接口。
(1)net.sf.cglib.proxy.InvocationHandler 這個接口和JDK提供的java.lang.reflect.InvocationHandler接口一樣。
(2)net.sf.cglib.proxy.MethodInterceptor 和InvocationHandler的作用一樣,不一樣的地方,是它的攔截方法提供了一個持有代理類的方法對象MethodProxy對象。如果方法內部調用了當前對象this的另一個方法,如果這個方法也需要被代理,那麼通過MethodProxy對象執行代理對象的方法就可以做到。
(3)net.sf.cglib.proxy.Dispatcher 每次調用代理對象的方法都會執行Dispatcher 接口的loadObject方法獲取被代理的對象。
(4)net.sf.cglib.proxy.ProxyRefDispatcher 作用和Dispatcher 一樣。
(5)net.sf.cglib.proxy.LazyLoader 懶加載被代理的對象,當第一次調用代理對象的方法時執行LazyLoader接口的loadObject方法獲取被代理的對象。
(6)net.sf.cglib.proxy.FixedValue 作用是爲代理的方法提供返回值,每個方法執行的時候都會調用。
(7)net.sf.cglib.proxy.NoOp 不做攔截,即不做回調,直接調用被代理對象的方法。
在CGLib回調時,通過實現net.sf.cglib.proxy.CallbackFilter接口還可以設置對不同方法執行不同的回調邏輯。這一點避免了像JDK動態代理的InvocationHandler接口方法對每個代理方法都回調問題。CallbackFilter接口的定義如下。
public interface CallbackFilter {
/**
*
* @param 被攔截的方法
* @return 返回回調接口在callbacks數組中的索引
*/
int accept(Method method);
/**
* Enhancer將使用這個接口,爲了提高性能,自定義的CallbackFilter應該
* 實現equals和hashCode方法
*/
boolean equals(Object o);
}
JDK動態代理通過java.lang.reflect.Proxy的newProxyInstance靜態方法創建代理。在Cglib中,則通過net.sf.cglib.proxy.Enhancer對象的重載的兩個create方法創建代理對象。
使用Cglib
MethodInterceptor 接口的使用
(1)定義需要被代理的類,示例如下。
public class NeedProxyObject {
public void execute() {
System.out.println("execute正在執行");
// 執行public方法
publicMethod();
// 執行protected方法
protectedMethod();
// 執行private方法
privateMethod();
}
public void publicMethod() {
System.out.println("publicMethod正在執行");
}
protected void protectedMethod() {
System.out.println("protectedMethod正在執行");
}
private void privateMethod() {
System.out.println("privateMethod正在執行");
}
}
(2)創建Cglib回調類,這裏我們以實現net.sf.cglib.proxy.MethodInterceptor接口爲例,代碼如下。
public class CGLIBMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
String methodName = method.getName();
try{
System.out.println(methodName + "方法執行開始");
// 執行被代理對象的方法
return proxy.invokeSuper(obj, args);
} finally {
System.out.println(methodName + "方法執行結束");
}
}
}
(3)編寫main方法爲NeedProxyObject對象的非私有方法添加執行日誌,代碼如下。
public static void main(String[] args) throws Exception {
// 實例化需要被代理的對象
NeedProxyObject needProxyObject = new NeedProxyObject();
// 創建CGLIB的Enhancer對象
Enhancer enhancer = new Enhancer();
// 以被代理類爲代理類的父類
enhancer.setSuperclass(needProxyObject.getClass());
// 設置代理方法執行時的回調對象
enhancer.setCallback(new CGLIBMethodInterceptor());
// 創建代理對象
NeedProxyObject proxy = (NeedProxyObject) enhancer.create();
// 執行代理方法
proxy.execute();
}
運行結果如下
execute方法執行開始
execute正在執行
publicMethod方法執行開始
publicMethod正在執行
publicMethod方法執行結束
protectedMethod方法執行開始
protectedMethod正在執行
protectedMethod方法執行結束
privateMethod正在執行
execute方法執行結束
通過CallbackFilter指定方法的回調
對於前面的例子,我們不想爲NeedProxyObject對象的publicMethod方法添加代理,通過CallbackFilter該如何做呢?
(1)實現CallbackFilter接口,示例如下。
public class CGLIBCallbackFilter implements CallbackFilter {
@Override
public int accept(Method method) {
if (method.getName().equals("publicMethod")) {
return 0;
}
return 1;
}
}
accept(Method method)方法的作用就是獲取方法的回調對象在回調對象數組中的索引。
(2)修改main方法的代碼,如下。
public static void main(String[] args) throws Exception {
// 實例化需要被代理的對象
NeedProxyObject needProxyObject = new NeedProxyObject();
// 創建CGLIB的Enhancer對象
Enhancer enhancer = new Enhancer();
// 以被代理類爲代理類的父類
enhancer.setSuperclass(needProxyObject.getClass());
// 設置回調過濾器
enhancer.setCallbackFilter(new CGLIBCallbackFilter());
// 設置代理方法執行時的回調對象
enhancer.setCallbacks(new Callback[]{NoOp.INSTANCE, new CGLIBMethodInterceptor()});
// 創建代理對象
NeedProxyObject proxy = (NeedProxyObject) enhancer.create();
// 執行代理方法
proxy.execute();
}
運行結果如下。
execute方法執行開始
execute正在執行
publicMethod正在執行
protectedMethod方法執行開始
protectedMethod正在執行
protectedMethod方法執行結束
privateMethod正在執行
execute方法執行結束
LazyLoader實現延遲加載
(1)創建需要延遲加載的類,我們以學生類爲例,如下
public class Student {
private String name; // 學生名稱
private int age; // 年齡
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
(2)實現LazyLoader接口創建Cglib回調類,代碼 示例如下,
public class StudentLazyLoader implements LazyLoader {
@Override
public Object loadObject() throws Exception {
System.out.println("LazyLoader 加載學生對象");
Student student = new Student();
student.setName("延遲加載");
student.setAge(20);
return student;
}
}
(3)創建代理並執行代理方法,我們以main方法爲執行入口,代碼如下。
public static void main(String[] args) throws Exception {
// 創建CGLIB的Enhancer對象
Enhancer enhancer = new Enhancer();
// 以被代理類爲代理類的父類
enhancer.setSuperclass(Student.class);
// 設置代理方法執行時的回調對象
enhancer.setCallback(new StudentLazyLoader());
// 創建代理對象
Student proxy = (Student) enhancer.create();
// 執行代理方法
System.out.println("執行代理");
System.out.println("學生名稱:" + proxy.getName());
System.out.println("學生年齡:" + proxy.getAge());
}
執行結果如下。
執行代理
LazyLoader 加載學生對象
學生名稱:延遲加載
學生年齡:20
通過運行結果可以看出,在執行代理對象的方法時,只會調用一次LazyLoader 接口的loadObject方法。
通過Dispatcher保證數據是最新的
我們還是以學生對象爲被代理對象,下面創建一個Dispatcher的回調類,代碼如下。
public class StudentDispatcher implements Dispatcher {
@Override
public Object loadObject() throws Exception {
System.out.println("Dispatcher 加載學生對象");
Student student = new Student();
student.setName("Dispatcher加載");
student.setAge(20);
return student;
}
}
創建代理並執行代理方法,我們以main方法爲執行入口,代碼如下。
public static void main(String[] args) throws Exception {
// 創建CGLIB的Enhancer對象
Enhancer enhancer = new Enhancer();
// 以被代理類爲代理類的父類
enhancer.setSuperclass(Student.class);
// 設置代理方法執行時的回調對象
enhancer.setCallback(new StudentDispatcher());
// 創建代理對象
Student proxy = (Student) enhancer.create();
// 執行代理方法
System.out.println("執行代理");
System.out.println("學生名稱:" + proxy.getName());
System.out.println("學生年齡:" + proxy.getAge());
}
執行結果如下。
執行代理
Dispatcher 加載學生對象
學生名稱:Dispatcher加載
Dispatcher 加載學生對象
學生年齡:20
Dispatcher和LazyLoader的實現都差不多,唯一的不同是LazyLoader只會執行一次,而Dispatcher會在每次執行代理方法時調用,因此它可以用來保證對象的數據是最新的。