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 }