本文實例講述了Java動態(tài)代理的兩種實現(xiàn)方式。分享給大家供大家參考,具體如下:
一說到動態(tài)代理,我們第一個想到肯定是大名鼎鼎的Spring AOP了。在AOP的源碼中用到了兩種動態(tài)代理來實現(xiàn)攔截切入功能:jdk動態(tài)代理和cglib動態(tài)代理。兩種方法同時存在,各有優(yōu)劣。jdk動態(tài)代理是由java內(nèi)部的反射機制來實現(xiàn)的,cglib動態(tài)代理是通過繼承來實現(xiàn)的,底層則是借助asm(Java 字節(jié)碼操控框架)來實現(xiàn)的(采用字節(jié)碼的方式,給A類創(chuàng)建一個子類B,子類B使用方法攔截的技術(shù)攔截所以父類的方法調(diào)用)。總的來說,反射機制在生成類的過程中比較高效,而asm在生成類之后的相關(guān)執(zhí)行過程中比較高效(可以通過將asm生成的類進(jìn)行緩存,這樣解決asm生成類過程低效問題)。還有一點必須注意:jdk動態(tài)代理的應(yīng)用前提,必須是目標(biāo)類基于統(tǒng)一的接口。如果沒有上述前提,jdk動態(tài)代理不能應(yīng)用。由此可以看出,jdk動態(tài)代理有一定的局限性,cglib這種第三方類庫實現(xiàn)的動態(tài)代理應(yīng)用更加廣泛,且在效率上更有優(yōu)勢。。
公用的接口和實現(xiàn)類
public interface UserService { public String getName(int id); public Integer getAge(int id);}public class UserServiceImpl implements UserService { @Override public String getName(int id) { System.out.println("------getName------"); return "Tom"; } @Override public Integer getAge(int id) { System.out.println("------getAge------"); return 10; }}
JDK的動態(tài)代理實現(xiàn)
jdk的動態(tài)代理,依賴的是反射包下的invocationHandler接口,我們的代理類實現(xiàn)invocationHandler,重寫invoke()方法,每當(dāng)我們的代理類調(diào)用方法時,都會默認(rèn)先經(jīng)過invoke()方法。
public class UserInvocationHandler implements InvocationHandler { private Object target; UserInvocationHandler() { super(); } UserInvocationHandler(Object target) { super(); this.target = target; } @Override public Object invoke(Object o, Method method, Object[] args) throws Throwable { if("getName".equals(method.getName())){ System.out.println("++++++before " + method.getName() + "++++++"); Object result = method.invoke(target, args); System.out.println("++++++after " + method.getName() + "++++++"); return result; }else{ Object result = method.invoke(target, args); return result; } }}
測試類
public class M { public static void main(String[] args) { UserService userService = new UserServiceImpl(); InvocationHandler invocationHandler = new UserInvocationHandler(userService); UserService userServiceProxy = (UserService) Proxy.newProxyInstance( userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), invocationHandler); System.out.println(userServiceProxy.getName(1)); System.out.println(userServiceProxy.getAge(1)); }}
測試效果
CGLIB的動態(tài)代理實現(xiàn)
cglib依賴的是cglib包下的methodInterceptor接口,每調(diào)用代理類的方法,都會調(diào)用intercept方法
public class CglibMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("------before " + methodProxy.getSuperName() + "------"); Object o1 = methodProxy.invokeSuper(o, args); System.out.println("------after " + methodProxy.getSuperName() + "------"); return o1; }}
測試類
public class M { public static void main(String[] args) { CglibMethodInterceptor cglibProxy = new CglibMethodInterceptor(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserServiceImpl.class); enhancer.setCallback(cglibProxy); UserService o = (UserService) enhancer.create(); o.getName(1); o.getAge(1); }}
測試結(jié)果
ps:cglib的動態(tài)代理,需要cglib.jar和asm.jar支持
附:點擊此處本站下載 cglib.jar asm.jar 。
希望本文所述對大家java程序設(shè)計有所幫助。
新聞熱點
疑難解答
圖片精選