1. 程式人生 > >CGlib和JDK動態代理

CGlib和JDK動態代理

nts 擴展 ons struct 具體實現 ram 輸出結果 one 機制

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.

System.out.println("hello everyone");

4. }

5. }

該類實現了創建子類的方法與代理的方法。getProxy(SuperClass.class)方法通過入參即父類的字節碼,通過擴展父類的class來創建代理對象intercept()方法攔截所有目標類方法的調用,obj表示目標類的實例,method為目標類方法的反射對象,args為方法的動態入參,proxy為代理類實例。proxy.invokeSuper(obj, args)通過代理類調用父類中的方法。

[java] view plain copy

1. public

class CglibProxy implements MethodInterceptor{

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動態代理