久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

如何從動態(tài)代理實現(xiàn)到Spring AOP

163次閱讀
沒有評論

共計 4999 個字符,預(yù)計需要花費 13 分鐘才能閱讀完成。

如何從動態(tài)代理實現(xiàn)到 Spring AOP,針對這個問題,這篇文章詳細介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

丸趣 TV 小編主要講了 Spring Aop 動態(tài)代理實現(xiàn)的兩種方式。

1. Spring AOP

Spring 是一個輕型容器,Spring 整個系列的最最核心的概念當屬 IoC、AOP。可見 AOP 是 Spring 框架中的核心之一,在應(yīng)用中具有非常重要的作用,也是 Spring 其他組件的基礎(chǔ)。AOP(Aspect Oriented Programming),即面向切面編程,可以說是 OOP(Object Oriented Programming,面向?qū)ο缶幊蹋┑难a充和完善。OOP 引入封裝、繼承、多態(tài)等概念來建立一種對象層次結(jié)構(gòu),用于模擬公共行為的一個集合。不過 OOP 允許開發(fā)者定義縱向的關(guān)系,但并不適合定義橫向的關(guān)系,例如日志功能。

關(guān)于 AOP 的基礎(chǔ)知識,并不是本文的重點,我們主要來看下 AOP 的核心功能的底層實現(xiàn)機制:動態(tài)代理的實現(xiàn)原理。AOP 的攔截功能是由 java 中的動態(tài)代理來實現(xiàn)的。在目標類的基礎(chǔ)上增加切面邏輯,生成增強的目標類(該切面邏輯或者在目標類函數(shù)執(zhí)行之前,或者目標類函數(shù)執(zhí)行之后,或者在目標類函數(shù)拋出異常時候執(zhí)行。不同的切入時機對應(yīng)不同的 Interceptor 的種類,如 BeforeAdviseInterceptor,AfterAdviseInterceptor 以及 ThrowsAdviseInterceptor 等)。

那么動態(tài)代理是如何實現(xiàn)將切面邏輯(advise)織入到目標類方法中去的呢?下面我們就來詳細介紹并實現(xiàn) AOP 中用到的兩種動態(tài)代理。

AOP 的源碼中用到了兩種動態(tài)代理來實現(xiàn)攔截切入功能:jdk 動態(tài)代理和 cglib 動態(tài)代理。兩種方法同時存在,各有優(yōu)劣。jdk 動態(tài)代理是由 java 內(nèi)部的反射機制來實現(xiàn)的,cglib 動態(tài)代理底層則是借助 asm 來實現(xiàn)的。總的來說,反射機制在生成類的過程中比較高效,而 asm 在生成類之后的相關(guān)執(zhí)行過程中比較高效(可以通過將 asm 生成的類進行緩存,這樣解決 asm 生成類過程低效問題)。

下面我們分別來示例實現(xiàn)這兩種方法。

2. JDK 動態(tài)代理 2.1 定義接口與實現(xiàn)類

public interface OrderService { public void save(UUID orderId, String name);
 public void update(UUID orderId, String name);
 public String getByName(String name);
}

上面代碼定義了一個被攔截對象接口,即橫切關(guān)注點。下面代碼實現(xiàn)被攔截對象接口。

public class OrderServiceImpl implements OrderService {
 private String user = null;
 public OrderServiceImpl() { }
 public OrderServiceImpl(String user) { this.setUser(user);
 }
 //...
 
 @Override
 public void save(UUID orderId, String name) { System.out.println( call save() 方法,save:  + name);
 }
 @Override
 public void update(UUID orderId, String name) { System.out.println( call update() 方法 
 }
 @Override
 public String getByName(String name) { System.out.println( call getByName() 方法 
 return  aoho 
 }
}

2.2 JDK 動態(tài)代理類

public class JDKProxy implements InvocationHandler {
 // 需要代理的目標對象
 private Object targetObject;
 
 public Object createProxyInstance(Object targetObject) {
 this.targetObject = targetObject;
 return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(),
 this.targetObject.getClass().getInterfaces(), this);
 }
 @Override
 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 // 被代理對象
 OrderServiceImpl bean = (OrderServiceImpl) this.targetObject;
 Object result = null;
 // 切面邏輯(advise),此處是在目標類代碼執(zhí)行之前
 System.out.println( ---before invoke---- 
 if (bean.getUser() != null) { result = method.invoke(targetObject, args);
 }
 System.out.println( ---after invoke---- 
 return result;
 }
 //...
}

上述代碼實現(xiàn)了動態(tài)代理類 JDKProxy,實現(xiàn) InvocationHandler 接口,并且實現(xiàn)接口中的 invoke 方法。當客戶端調(diào)用代理對象的業(yè)務(wù)方法時,代理對象執(zhí)行 invoke 方法,invoke 方法把調(diào)用委派給 targetObject,相當于調(diào)用目標對象的方法,在 invoke 方法委派前判斷權(quán)限,實現(xiàn)方法的攔截。

2.3 測試

public class AOPTest { public static void main(String[] args) { JDKProxy factory = new JDKProxy();
 //Proxy 為 InvocationHandler 實現(xiàn)類動態(tài)創(chuàng)建一個符合某一接口的代理實例  
 OrderService orderService = (OrderService) factory.createProxyInstance(new OrderServiceImpl( aoho));
 // 由動態(tài)生成的代理對象來 orderService  代理執(zhí)行程序
 orderService.save(UUID.randomUUID(),  aoho 
 }
}

結(jié)果如下:

---before invoke----
call save() 方法,save:aoho
---after invoke----

3. CGLIB 字節(jié)碼生成 3.1 要代理的類

CGLIB 既可以對接口的類生成代理,也可以針對類生成代理。示例中,實現(xiàn)對類的代理。

public class OrderManager {
 private String user = null;
 public OrderManager() { }
 public OrderManager(String user) { this.setUser(user);
 }
 //...
 public void save(UUID orderId, String name) { System.out.println( call save() 方法,save:  + name);
 }
 public void update(UUID orderId, String name) { System.out.println( call update() 方法 
 }
 public String getByName(String name) { System.out.println( call getByName() 方法 
 return  aoho 
 }
}

該類的實現(xiàn)和上面的接口實現(xiàn)一樣,為了保持統(tǒng)一。

3.2 CGLIB 動態(tài)代理類

public class CGLibProxy implements MethodInterceptor {
 // CGLib 需要代理的目標對象
 private Object targetObject;
 public Object createProxyObject(Object obj) {
 this.targetObject = obj;
 Enhancer enhancer = new Enhancer();
 enhancer.setSuperclass(obj.getClass());
 // 回調(diào)方法的參數(shù)為代理類對象 CglibProxy,最后增強目標類調(diào)用的是代理類對象 CglibProxy 中的 intercept 方法  
 enhancer.setCallback(this);
 // 增強后的目標類
 Object proxyObj = enhancer.create();
 //  返回代理對象
 return proxyObj;
 }
 @Override
 public Object intercept(Object proxy, Method method, Object[] args,
 MethodProxy methodProxy) throws Throwable {
 Object obj = null;
 // 切面邏輯(advise),此處是在目標類代碼執(zhí)行之前
 System.out.println( ---before intercept---- 
 obj = method.invoke(targetObject, args);
 System.out.println( ---after intercept---- 
 return obj;
 }
}

上述實現(xiàn)了創(chuàng)建子類的方法與代理的方法。getProxy(SuperClass.class) 方法通過入?yún)⒓锤割惖淖止?jié)碼,擴展父類的 class 來創(chuàng)建代理對象。intercept() 方法攔截所有目標類方法的調(diào)用,obj 表示目標類的實例,method 為目標類方法的反射對象,args 為方法的動態(tài)入?yún)ⅲ琺ethodProxy 為代理類實例。method.invoke(targetObject, args) 通過代理類調(diào)用父類中的方法。

3.3 測試

public class AOPTest { public static void main(String[] args) { OrderManager order = (OrderManager) new CGLibProxy().createProxyObject(new OrderManager( aoho));
 order.save(UUID.randomUUID(),  aoho 
 }

結(jié)果如下:

---before intercept----
call save() 方法,save:aoho
---after intercept----

4. 總結(jié)

主要講了 Spring Aop 動態(tài)代理實現(xiàn)的兩種方式,并分別介紹了其優(yōu)缺點。jdk 動態(tài)代理的應(yīng)用前提是目標類基于統(tǒng)一的接口。如果沒有該前提,jdk 動態(tài)代理不能應(yīng)用。由此可以看出,jdk 動態(tài)代理有一定的局限性,cglib 這種第三方類庫實現(xiàn)的動態(tài)代理應(yīng)用更加廣泛,且在效率上更有優(yōu)勢。

JDK 動態(tài)代理機制是委托機制,不需要以來第三方的庫,只要要 JDK 環(huán)境就可以進行代理,動態(tài)實現(xiàn)接口類,在動態(tài)生成的實現(xiàn)類里面委托為 hanlder 去調(diào)用原始實現(xiàn)類方法;CGLib 必須依賴于 CGLib 的類庫,使用的是繼承機制,是被代理類和代理類繼承的關(guān)系,所以代理類是可以賦值給被代理類的,如果被代理類有接口,那么代理類也可以賦值給接口。

關(guān)于如何從動態(tài)代理實現(xiàn)到 Spring AOP 問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注丸趣 TV 行業(yè)資訊頻道了解更多相關(guān)知識。

正文完
 
丸趣
版權(quán)聲明:本站原創(chuàng)文章,由 丸趣 2023-08-17發(fā)表,共計4999字。
轉(zhuǎn)載說明:除特殊說明外本站除技術(shù)相關(guān)以外文章皆由網(wǎng)絡(luò)搜集發(fā)布,轉(zhuǎn)載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 聂拉木县| 洪湖市| 福海县| 特克斯县| 和平县| 大连市| 拜城县| 黎平县| 广东省| 南召县| 太仓市| 武清区| 桂阳县| 晋城| 宁明县| 桃园县| 镇平县| 日喀则市| 红安县| 手游| 外汇| 绥棱县| 揭东县| 山丹县| 衡阳市| 临泉县| 双峰县| 兴宁市| 凤庆县| 彰化市| 萨迦县| 凤山县| 三明市| 凉城县| 海口市| 东乌| 修武县| 芜湖县| 海淀区| 平湖市| 宁陕县|