實戰CGLib系列文章java
本篇介紹經過MethodInterceptor和Enhancer實現一個動態代理。編程
1、首先說一下JDK中的動態代理:框架
JDK中的動態代理是經過反射類Proxy以及InvocationHandler回調接口實現的,不瞭解的同窗請參考個人這篇Blog:Java動態代理詳解 http://shensy.iteye.com/blog/1698197 spa
可是,JDK中所要進行動態代理的類必需要實現一個接口,也就是說只能對該類所實現接口中定義的方法進行代理,這在實際編程中具備必定的侷限性,並且使用反射的效率也並非很高。代理
2、使用CGLib實現:orm
使用CGLib實現動態代理,徹底不受代理類必須實現接口的限制,並且CGLib底層採用ASM字節碼生成框架,使用字節碼技術生成代理類,比使用Java反射效率要高。惟一須要注意的是,CGLib不能對聲明爲final的方法進行代理,由於CGLib原理是動態生成被代理類的子類。blog
下面,將經過一個實例介紹使用CGLib實現動態代理。接口
一、被代理類:get
首先,定義一個類,該類沒有實現任何接口,包含兩個方法。it
Java代碼
public class ConcreteClassNoInterface {
public String getConcreteMethodA(String str){
System.out.println("ConcreteMethod A ... "+str);
return str;
}
public int getConcreteMethodB(int n){
System.out.println("ConcreteMethod B ... "+n);
return n+10;
}
}
二、攔截器:
定義一個攔截器。在調用目標方法時,CGLib會回調MethodInterceptor接口方法攔截,來實現你本身的代理邏輯,相似於JDK中的InvocationHandler接口。
Java代碼
public class ConcreteClassInterceptor implements MethodInterceptor{
public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) throws Throwable {
System.out.println("Before:"+method);
Object object=proxy.invokeSuper(obj, arg);
System.out.println("After:"+method);
return object;
}
}
參數:Object爲由CGLib動態生成的代理類實例,Method爲上文中實體類所調用的被代理的方法引用,Object[]爲參數值列表,MethodProxy爲生成的代理類對方法的代理引用。
返回:從代理實例的方法調用返回的值。
其中,proxy.invokeSuper(obj,arg):
調用代理類實例上的proxy方法的父類方法(即實體類ConcreteClassNoInterface中對應的方法)
在這個示例中,只在調用被代理類方法先後各打印了一句話,固然實際編程中能夠是其它複雜邏輯。
三、生成動態代理類:
Java代碼
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(ConcreteClassNoInterface.class);
enhancer.setCallback(new ConcreteClassInterceptor());
ConcreteClassNoInterface ccni=(ConcreteClassNoInterface)enhancer.create();
這裏Enhancer類是CGLib中的一個字節碼加強器,它能夠方便的對你想要處理的類進行擴展,之後會常常看到它。
首先將被代理類ConcreteClassNoInterface設置成父類,而後設置攔截器ConcreteClassInterceptor,最後執行enhancer.create()動態生成一個代理類,並從Object強制轉型成父類型ConcreteClassNoInterface。
最後,在代理類上調用方法:
Java代碼
ccni.getConcreteMethodA("shensy");
ccni.getConcreteMethodB(0);
查看控制檯輸出:
控制檯代碼
Before :public java.lang.String generic.cglib.proxy.ConcreteClassNoInterface.getConcreteMethodA(java.lang.String)
ConcreteMethod A ... shensy
After :public java.lang.String generic.cglib.proxy.ConcreteClassNoInterface.getConcreteMethodA(java.lang.String)
Before :public int generic.cglib.proxy.ConcreteClassNoInterface.getConcreteMethodB(int)
ConcreteMethod B ... 0
After :public int generic.cglib.proxy.ConcreteClassNoInterface.getConcreteMethodB(int)
能夠看到,攔截器在調用被代理類方法先後都執行了print操做。