一、原理區別
Java動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理。
而cglib動態代理是利用asm開源包,對代理對象類的class文件加載進來,通過修改其字節碼生成子類來處理
JDK動態代理和CGLIB字節碼生成的區別?
(1)JDK動態代理只能對實現了接口的類生成代理,而不能針對類
(2)CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法
因爲是繼承,所以該類或方法最好不要聲明成final
二,代理實現
JDK動態代理
1.實現InvocationHandler
2.提供接口public class MyInvocationHandler implements InvocationHandler{ /** * 要代理的目標對象 */ private Object target; public MyInvocationHandler(Object target) { this.target = target; } /** * 執行方法 * @param proxy * @param method * @param args * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("方法執行之前..."); Object result = method.invoke(this.target,args); System.out.println("方法執行之後..."); return result; } /** * 生成代理對象 * @return */ public Object getProxy(){ return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), this.target.getClass().getInterfaces(),this); } }
3.子類實現接口public interface Person{ void makeFriend(String name); }
4.測試類public class ZhangSan implements Person { @Override public void makeFriend(String name) { System.out.println("和"+name+"交了個朋友"); } }
5.打印結果public class ProxyTest { public static void main(String[] args) { MyInvocationHandler myInvocationHandler = new MyInvocationHandler(new ZhangSan()); Person person = (Person) myInvocationHandler.getProxy(); //System.out.println(person); person.makeFriend("林志玲"); } }
方法執行之前...
和林志玲交了個朋友
方法執行之後...
CGLIB動態代理1.提供目標類
2.生成代理類public class XiaoMing { void sayHello(){ System.out.println("hello everyone"); } }
3.測試public class CglibProxy implements MethodInterceptor { public Object getProxy(Class clazz){ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(clazz);//設置代理類的父類爲目標類 enhancer.setCallback(this);//回調 return enhancer.create();//生成代理類 } @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable { //生成代理類是子類,因此調用父類的方法 Object obj = proxy.invokeSuper(o, args); return obj; } }
4.打印結果public class CglibTest { public static void main(String[] args) { CglibProxy cglibProxy = new CglibProxy(); XiaoMing xiaoMing = (XiaoMing) cglibProxy.getProxy(XiaoMing.class); xiaoMing.sayHello(); } }
hello everyone
三,總結
jdk代理
代理對象和目標對象實現了相同了接口,目標對象作爲代理對象的一個屬性在維護,此代理模式在使用時需要制定具體目標對象,並且只針對實現了接口的類生成代理
cglib代理
cglib代理是針對類實現代理,生成的是目標類的子類代理對象,覆蓋其所有方法,所以目標類或方法不能聲明成final的。如果目標對象實現了接口,可以強制使用CGLIB實現代理(添加CGLIB庫,並在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)
cglib動態創建代理對象性能比jdk創建效率要高,對於單例對象,cglib更適合,不用頻繁創建對象;反之jdk代理更適合