java 動態代理模式(jdk和cglib)

 1 package proxy.dynamicproxy;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 import java.lang.reflect.Proxy;
 6 
 7 
 8 /**
 9  * 需要實現InvocationHandler接口,內部維護一個實際類實例
10  *
11  */
12 public class JdkProxyHandler implements InvocationHandler {
13 
14     private Object realObject;
15 
16     public Object proxy(Object realObject){
17         this.realObject = realObject;
18         return Proxy.newProxyInstance(this.realObject.getClass().getClassLoader(),
19                 this.realObject.getClass().getInterfaces(), this);
20     }
21 
22     /**
23      *
24      * @param proxy 動態生成的代理類實例
25      * @param method 方法實例
26      * @param args 方法參數
27      * @return
28      * @throws Throwable
29      */
30     @Override
31     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
32         System.out.println("我是代理人:大明星唱歌開始前,我先宣傳一下:巴拉巴拉。。。");
33 
34         // 調用實際類的方法,並傳入參數,內部是反射機制
35         Object ret = method.invoke(this.realObject, args);
36 
37         System.out.println("我是代理人:大明星唱歌完畢了,我來總結一下:巴拉巴拉。。。");
38 
39         return ret;
40     }
41 }
 1 package proxy.dynamicproxy;
 2 
 3 import net.sf.cglib.proxy.Enhancer;
 4 import net.sf.cglib.proxy.MethodInterceptor;
 5 import net.sf.cglib.proxy.MethodProxy;
 6 
 7 import java.lang.reflect.Method;
 8 
 9 /**
10  * 需要實現MethodInterceptor接口
11  * cglib相關依賴:
12  * ant-1.6.2.jar
13  * asm-3.1.jar
14  * asm-util-3.1.jar
15  * cglib-2.2.2.jar
16  */
17 public class CglibProxyHandler implements MethodInterceptor {
18 
19     public Object proxy(Object realObject){
20 
21         // 使用字節碼增強器 四個固定步驟:
22         // 1、new字節碼增強器
23         // 2、設置當前類實例爲回調
24         // 3、將實際類實例設置爲父類
25         // 4、創建一個代理類
26         Enhancer enhancer = new Enhancer();
27         enhancer.setCallback(this);
28         enhancer.setSuperclass(realObject.getClass());
29         // 這裏會生成代理類、代理類的FastClass輔助類、實際類的FastClass輔助類
30         // 輔助類爲代理類和實際類的每個方法生成一個唯一的id
31         // 用於在調用intercept方法時,通過唯一id就可以調用對應的方法
32         // 不再走反射機制,提高性能
33         return enhancer.create();
34     }
35 
36     /**
37      *
38      * @param o 代理類的實例
39      * @param method 方法實例
40      * @param objects 方法參數
41      * @param methodProxy 方法代理
42      * @return
43      * @throws Throwable
44      */
45     @Override
46     public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
47 
48         System.out.println("我是代理人:大明星唱歌開始前,我先宣傳一下:巴拉巴拉。。。");
49 
50         // 這裏如果使用 method.invoke方法,就等同於走了反射機制去調用方法,性能不高
51         // 而且還需要另外維護實際類實例
52         // Object ret = method.invoke(this.realObject, objects);
53 
54         Object ret = methodProxy.invokeSuper(o, objects);
55 
56         System.out.println("我是代理人:大明星唱歌完畢了,我來總結一下:巴拉巴拉。。。");
57 
58         return ret;
59     }
60 }
 1 package proxy.dynamicproxy;
 2 
 3 import net.sf.cglib.core.DebuggingClassWriter;
 4 import proxy.staticproxy.IStar;
 5 import proxy.staticproxy.RealStar;
 6 
 7 public class Test {
 8     public static void main(String[] args) {
 9 
10         /**
11          * 還是以“代理人”和“大明星”爲例
12          * jdk動態代理:適用於大明星實現某接口的情況,且只能用於實現接口的情況
13          *      不能用於未實現任何接口的類,因爲生成的動態代理類要繼承自Proxy、同時實現大明星接口。
14          * cglib動態代理:適用於任何類。它是採用動態代理類直接繼承大明星類的方式,將大明星當作父類
15          *      覆寫大明星類的所有方法(除final修飾的方法,wait方法,notify方法)
16          *
17          * 優缺點:
18          * jdk方式,只能針對接口,底層直接寫字節碼的方式生成代理類,所以生成代理類速度快
19          *      但是代理類執行方法時,通過反射的方式去執行,速度不如cglib方式
20          * cglib方式,可以適用於任何類,底層使用ASM框架生成字節碼,因爲採用FastClass機制
21          *      在生成代理類的同時還要生成代理類和大明星類的對應FastClass類(輔助類)
22          *      這兩個輔助類的作用是:對應FastClass輔助類會爲代理類和大明星類的每一個方法
23          *      (除final修飾的方法,wait方法,notify方法)生成唯一id,這樣在後面的調用方法時
24          *      不再通過反射去執行邏輯,而是直接根據id找到對應的方法去執行,提高性能,但相對的,生成字節碼速度較慢
25          */
26         boolean isUseJdkProxy = false;
27 
28         if (isUseJdkProxy) {
29             System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
30 
31             IStar star = (IStar) new JdkProxyHandler().proxy(new RealStar());
32             star.sing();
33         }
34         else {
35 
36             System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,
37                     "C:\\Users\\Administrator\\IdeaProjects\\untitled\\cglibClass");
38 
39             IStar star = (IStar) new CglibProxyHandler().proxy(new RealStar());
40 
41             // 這一步裏面的具體流程:
42             // 動態代理類的sing方法 --> CglibProxyHandler的intercept方法
43             //  --> 實際類執行前的行爲代理 --> MethodProxy.invokeSuper方法
44             //  --> 根據唯一id在FastClass裏找到對應的實際方法
45             //  --> 代理類的FastClass內部:讓代理類調用實際方法
46             //  --> 代理類的實際方法內部一般就是直接調用父類(被代理類)的方法
47             //  --> 返回父類方法的返回值
48             star.sing();
49 
50         }
51     }
52 }

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章