Java動(dòng)態(tài)代理的兩種實(shí)現(xiàn)方式詳解【附相關(guān)jar文件下載】
本文實(shí)例講述了Java動(dòng)態(tài)代理的兩種實(shí)現(xiàn)方式。分享給大家供大家參考,具體如下:
一說(shuō)到動(dòng)態(tài)代理,我們第一個(gè)想到肯定是大名鼎鼎的Spring AOP了。在AOP的源碼中用到了兩種動(dòng)態(tài)代理來(lái)實(shí)現(xiàn)攔截切入功能:jdk動(dòng)態(tài)代理和cglib動(dòng)態(tài)代理。兩種方法同時(shí)存在,各有優(yōu)劣。jdk動(dòng)態(tài)代理是由java內(nèi)部的反射機(jī)制來(lái)實(shí)現(xiàn)的,cglib動(dòng)態(tài)代理是通過(guò)繼承來(lái)實(shí)現(xiàn)的,底層則是借助asm(Java 字節(jié)碼操控框架)來(lái)實(shí)現(xiàn)的(采用字節(jié)碼的方式,給A類創(chuàng)建一個(gè)子類B,子類B使用方法攔截的技術(shù)攔截所以父類的方法調(diào)用)??偟膩?lái)說(shuō),反射機(jī)制在生成類的過(guò)程中比較高效,而asm在生成類之后的相關(guān)執(zhí)行過(guò)程中比較高效(可以通過(guò)將asm生成的類進(jìn)行緩存,這樣解決asm生成類過(guò)程低效問(wèn)題)。還有一點(diǎn)必須注意:jdk動(dòng)態(tài)代理的應(yīng)用前提,必須是目標(biāo)類基于統(tǒng)一的接口。如果沒(méi)有上述前提,jdk動(dòng)態(tài)代理不能應(yīng)用。由此可以看出,jdk動(dòng)態(tài)代理有一定的局限性,cglib這種第三方類庫(kù)實(shí)現(xiàn)的動(dòng)態(tài)代理應(yīng)用更加廣泛,且在效率上更有優(yōu)勢(shì)。。
公用的接口和實(shí)現(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的動(dòng)態(tài)代理實(shí)現(xiàn)
jdk的動(dòng)態(tài)代理,依賴的是反射包下的invocationHandler接口,我們的代理類實(shí)現(xiàn)invocationHandler,重寫(xiě)invoke()方法,每當(dāng)我們的代理類調(diào)用方法時(shí),都會(huì)默認(rèn)先經(jīng)過(guò)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; } } }
測(cè)試類
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)); } }
測(cè)試效果
CGLIB的動(dòng)態(tài)代理實(shí)現(xiàn)
cglib依賴的是cglib包下的methodInterceptor接口,每調(diào)用代理類的方法,都會(huì)調(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; } }
測(cè)試類
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); } }
測(cè)試結(jié)果
ps:cglib的動(dòng)態(tài)代理,需要cglib.jar和asm.jar支持
附:點(diǎn)擊此處本站下載 cglib.jar asm.jar 。
更多關(guān)于java算法相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Java數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Java操作DOM節(jié)點(diǎn)技巧總結(jié)》、《Java文件與目錄操作技巧匯總》和《Java緩存操作技巧匯總》
希望本文所述對(duì)大家java程序設(shè)計(jì)有所幫助。
- 詳解Java JDK動(dòng)態(tài)代理
- 詳解Java Cglib動(dòng)態(tài)代理
- Java簡(jiǎn)單實(shí)現(xiàn)動(dòng)態(tài)代理模式過(guò)程解析
- Java JDK動(dòng)態(tài)代理實(shí)現(xiàn)原理實(shí)例解析
- 詳細(xì)分析java 動(dòng)態(tài)代理
- Java使用JDK與Cglib動(dòng)態(tài)代理技術(shù)統(tǒng)一管理日志記錄
- Java動(dòng)態(tài)代理語(yǔ)法Proxy類原理詳解
- Java代理模式實(shí)例詳解【靜態(tài)代理與動(dòng)態(tài)代理】
- JAVA使用動(dòng)態(tài)代理對(duì)象進(jìn)行敏感字過(guò)濾代碼實(shí)例
- 詳解JAVA動(dòng)態(tài)代理
- Java動(dòng)態(tài)代理和反射機(jī)制詳解
- Java兩種方式實(shí)現(xiàn)動(dòng)態(tài)代理
相關(guān)文章
Struts2動(dòng)態(tài)結(jié)果集代碼示例
這篇文章主要介紹了Struts2動(dòng)態(tài)結(jié)果集的有關(guān)內(nèi)容,涉及具體代碼示例,具有一定參考價(jià)值,需要的朋友可以了解下。2017-09-09Spring Security在標(biāo)準(zhǔn)登錄表單中添加一個(gè)額外的字段
這篇文章主要介紹了Spring Security在標(biāo)準(zhǔn)登錄表單中添加一個(gè)額外的字段,我們將重點(diǎn)關(guān)注兩種不同的方法,以展示框架的多功能性以及我們可以使用它的靈活方式。 需要的朋友可以參考下2019-05-05詳解spring boot實(shí)現(xiàn)多數(shù)據(jù)源代碼實(shí)戰(zhàn)
本篇文章主要介紹了詳解spring boot實(shí)現(xiàn)多數(shù)據(jù)源代碼實(shí)戰(zhàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07使用System.exit()來(lái)優(yōu)雅地終止SpringBoot項(xiàng)目的代碼示例
System.exit() 方法是 Java 中用于退出程序的方法,它接受一個(gè)整數(shù)參數(shù),通常被用來(lái)指示程序的退出狀態(tài),本文給大家介紹了如何使用System.exit()來(lái)優(yōu)雅地終止SpringBoot項(xiàng)目,需要的朋友可以參考下2024-08-08SpringBoot應(yīng)用能直接運(yùn)行java -jar的原因分析
這篇文章主要介紹了SpringBoot應(yīng)用為什么能直接運(yùn)行java -jar,首先明確一點(diǎn),普通jar包是不能直接運(yùn)行的,比如工具類jar,要能運(yùn)行,至少得要一個(gè)main函數(shù)作為入口吧?本文給大家介紹了詳細(xì)的原因分析,需要的朋友可以參考下2024-03-03