使用CGLIB動態代理
11、使用CGLIB動態代理
Cglib是一個優秀的動態代理框架,它的底層使用ASM在內存中動態的生成被代理類的子類。使用CGLIB即使被代理類沒有實現任何接口也可以實現動態代理功能。CGLIB具有簡單易用,它的運行速度要遠遠快于JDK的Proxy動態代理:
使用CGLIB需要導入以下兩個jar文件:
asm.jar – CGLIB的底層實現。
cglib.jar – CGLIB的核心jar包。
CGLIB的核心類:
net.sf.cglib.proxy.Enhancer – 主要的增強類
net.sf.cglib.proxy.MethodInterceptor – 主要的方法攔截類,它是Callback接口的子接口,需要用戶實現
net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method類的代理類,可以方便的實現對源對象方法的調用,如使用:
Object o = methodProxy.invokeSuper(proxy, args);//雖然第一個參數是被代理對象,也不會出現死循環的問題。
費話少說,上代碼:
1、使用CGLIB的代理:
以下測試代理一個沒有實現任何接口的Person類:
@Test
public void testProxy1() throws Exception {
final Person p1 = new Person(); //Person類沒有實現任何接口
Enhancer en = new Enhancer(); //聲明增加類實例
en.setSuperclass(Person.class); //設置被代理類字節碼,CGLIB根據字節碼生成被代理類的子類
en.setCallback(new MethodInterceptor() { //設置回調函數,即一個方法攔截
public Object intercept(Object target, Method method,
Object[] args, MethodProxy proxy) throws Throwable {
Object o = method.invoke(p1,args); //注意參數p1,仍然為外部聲明的源對象,且Method為JDK的Method反射
System.err.println("After...");
return o;
}
});
Person p = (Person) en.create(); //通過create方法返回Person類的代理
System.err.println(p.getClass());//被代理的對象
p.sayHi("Hello");
}
2、以下測試代理一個擁有接口的類:
IAnimal是接口,Dog是實現類,具體代碼如下:
@Test
public void testProxy2() throws Exception {
final Dog dog = new Dog(); //聲明被代理對象
Enhancer en = new Enhancer(); //聲明CGLIB增強類
en.setSuperclass(IAnimal.class); //設置接口類,也可以設置成dog實現類,會影響create返回的對象
en.setCallback(new MethodInterceptor() {
public Object intercept(Object target, Method method,
Object[] args, MethodProxy proxy) throws Throwable {
System.err.println("Before...");
Object o = method.invoke(dog, args);
System.err.println("After...");
return o;
}
});
//Dog dog2 = (Dog) en.create();//必須轉型為接口,否則拋出ClassCastException
IAnimal dog2 = (IAnimal)en.create();
dog2.eat();
}
說明:
由于上例中,設置了en.setSuperclass(IAnimal.class),所以en.create()方法,返回的對象,必須要轉換成IAnimal接口。如果轉換成Dog則會拋出ClassCastException。
3、將CGLIB再做一個簡單的包裝:
class CglibProxy implements MethodInterceptor{
private Object srcTarget;
private CglibProxy(Object o){
this.srcTarget = o;
}
@SuppressWarnings("unchecked")
public static <T>T proxyTarget(T t){
Enhancer en = new Enhancer();
en.setSuperclass(t.getClass());
en.setCallback(new CglibProxy(t));
T tt = (T) en.create();
return tt;
}
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.err.println("攔截前...");
Object o = method.invoke(srcTarget, args);
System.err.println("攔截后....");
return o;
}
}
包裝以后的調用代碼如下,主要是快速的實現獲取被代理類:
Person p = CglibProxy.proxyTarget(new Person());
p.sayHi("HJello");
IAnimal dog = CglibProxy.proxyTarget(new Dog());
dog.eat();
4、使用靜態方法代理一個沒有接口的對象
以下代碼,包含在一個測試方法或是main方法中運行:
final Person src = new Person();
//直接使用靜態方法代理一個對象
Person p = (Person) Enhancer.create(Person.class,new MethodInterceptor(){
public Object intercept(Object proxyedObj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.err.println("Hello");
//使用原生的方法調用,注意里面的src
//Object oo = method.invoke(src, args);
//使用MethodProxy調用父類的代碼,同樣有效
Object oo = proxy.invokeSuper(proxyedObj, args);
return oo;
}
});
System.err.println(p.getClass());
p.abc();