CGlib和JDK動態代理
一、CGlib動態代理
JDK實現動態代理需要實現類通過接口定義業務方法,對於沒有接口的類,如何實現動態代理呢,這就需要CGLib了。CGLib采用了非常底層的1:字節碼技術,其原理是通過字節碼技術為一個類創建子類,並在子類中采用2:方法攔截的技術攔截所有父類方法的調用,順勢織入橫切邏輯。JDK動態代理與CGLib動態代理均是實現Spring AOP的基礎。
字節碼技術:參考:http://note.youdao.com/noteshare?id=13453e8d815d3102938a02881b6f418f&sub=E56D1E6223FC4CA8BF072CD045301EFA
CGLib創建的動態代理對象性能比JDK創建的動態代理對象的性能高不少,但是CGLib在創建代理對象時所花費的時間卻比JDK多得多,所以對於單例的對象,因為無需頻繁創建對象,用CGLib合適,反之,使用JDK方式要更為合適一些。同時,由於CGLib由於是采用動態創建子類的方法,對於final方法,無法進行代理。
簡單的實現舉例:
這是一個需要被代理的類,也就是父類,通過字節碼技術創建這個類的子類,實現動態代理。
[java] view plain copy
1. public class SayHello {
2. public void say(){
3.
4. }
5. }
該類實現了創建子類的方法與代理的方法。getProxy(SuperClass.class)方法通過入參即父類的字節碼,通過擴展父類的class來創建代理對象。intercept()方法攔截所有目標類方法的調用,obj表示目標類的實例,method為目標類方法的反射對象,args為方法的動態入參,proxy為代理類實例。proxy.invokeSuper(obj, args)通過代理類調用父類中的方法。
[java] view plain copy
1. public
2. private Enhancer enhancer = new Enhancer();
3. public Object getProxy(Class clazz){
4. //設置需要創建子類的類
5. enhancer.setSuperclass(clazz);
6. enhancer.setCallback(this);
7. //通過字節碼技術動態創建子類實例
8. return enhancer.create();
9. }
10. //實現MethodInterceptor接口方法
11. public Object intercept(Object obj, Method method, Object[] args,
12. MethodProxy proxy) throws Throwable {
13. System.out.println("前置代理");
14. //通過代理類調用父類中的方法
15. Object result = proxy.invokeSuper(obj, args);
16. System.out.println("後置代理");
17. return result;
18. }
19. }
具體實現類:
[java] view plain copy
1. public class DoCGLib {
2. public static void main(String[] args) {
3. CglibProxy proxy = new CglibProxy();
4. //通過生成子類的方式創建代理類
5. SayHello proxyImp = (SayHello)proxy.getProxy(SayHello.class);
6. proxyImp.say();
7. }
8. }
輸出結果:
[plain] view plain copy
1. 前置代理
2. hello everyone
3. 後置代理
二、JDK動態代理
使用動態代理的五大步驟
1.通過實現InvocationHandler接口來自定義自己的InvocationHandler;
2.通過Proxy.getProxyClass獲得動態代理類
3.通過反射機制獲得代理類的構造方法,方法簽名為getConstructor(InvocationHandler.class)
4.通過構造函數,獲得代理對象,並將自定義的InvocationHandler實例對象傳為參數傳入
5.通過代理對象調用目標方法
public class ObjectProxy implements InvocationHandler {
Object target = null;
List<BeforeAdvice> beforeList = new ArrayList<BeforeAdvice>();
List<AfterAdvice> afterList = new ArrayList<AfterAdvice>();
public ObjectProxy() {
super();
// TODO Auto-generated constructor stub
}
public ObjectProxy(Object target) {
super();
this.target = target;
try{
//解析advice.xml中所有的前置通知--得到class的值--->通過反射得到類的對象
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse("src//advice.xml");
//遍歷前置通知
NodeList beforeNodeList = doc.getElementsByTagName("beforeAdvice");
for(int i=0;i<beforeNodeList.getLength();i++){
Element beforeElement =(Element) beforeNodeList.item(i);
String classValue = beforeElement.getAttribute("class"); //類的完整路徑
Class clz = Class.forName(classValue);
BeforeAdvice obj = (BeforeAdvice)clz.newInstance();
beforeList.add(obj);
}
//遍歷後置通知
NodeList afterNodeList = doc.getElementsByTagName("afterAdvice");
for(int i=0;i<afterNodeList.getLength();i++){
Element afterElement =(Element) afterNodeList.item(i);
String classValue = afterElement.getAttribute("class"); //類的完整路徑
Class clz = Class.forName(classValue);
AfterAdvice obj = (AfterAdvice)clz.newInstance();
afterList.add(obj);
}
}catch(Exception e){
e.printStackTrace();
}
}
/**
* 偽裝成目標類之後,要執行的方法
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//短信驗證
for(BeforeAdvice bf:beforeList){
//對method目標方法進行判斷,執行響應的前置切面業務
bf.Before();
}
//目標方法
Object result = method.invoke(target, args);
//日誌記錄
for(AfterAdvice af:afterList){
//對method目標方法進行判斷,執行響應的後置切面業務
af.After();
}
return result;
}
/**
* 獲得代理類的對象
* @param obj
* @return
*/
public static Object getProxyBean(Object obj){
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),new ObjectProxy(obj));
}
}
public static void main(String[] args) {
Idog dog = (Idog)ObjectProxy.getProxyBean(new Dog());
dog.say();
}
CGlib和JDK動態代理