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

如何從動態代理實現到Spring AOP

161次閱讀
沒有評論

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

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

丸趣 TV 小編主要講了 Spring Aop 動態代理實現的兩種方式。

1. Spring AOP

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

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

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

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

下面我們分別來示例實現這兩種方法。

2. JDK 動態代理 2.1 定義接口與實現類

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

上面代碼定義了一個被攔截對象接口,即橫切關注點。下面代碼實現被攔截對象接口。

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 動態代理類

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),此處是在目標類代碼執行之前
 System.out.println( ---before invoke---- 
 if (bean.getUser() != null) { result = method.invoke(targetObject, args);
 }
 System.out.println( ---after invoke---- 
 return result;
 }
 //...
}

上述代碼實現了動態代理類 JDKProxy,實現 InvocationHandler 接口,并且實現接口中的 invoke 方法。當客戶端調用代理對象的業務方法時,代理對象執行 invoke 方法,invoke 方法把調用委派給 targetObject,相當于調用目標對象的方法,在 invoke 方法委派前判斷權限,實現方法的攔截。

2.3 測試

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

結果如下:

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

3. CGLIB 字節碼生成 3.1 要代理的類

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

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 
 }
}

該類的實現和上面的接口實現一樣,為了保持統一。

3.2 CGLIB 動態代理類

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());
 // 回調方法的參數為代理類對象 CglibProxy,最后增強目標類調用的是代理類對象 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),此處是在目標類代碼執行之前
 System.out.println( ---before intercept---- 
 obj = method.invoke(targetObject, args);
 System.out.println( ---after intercept---- 
 return obj;
 }
}

上述實現了創建子類的方法與代理的方法。getProxy(SuperClass.class) 方法通過入參即父類的字節碼,擴展父類的 class 來創建代理對象。intercept() 方法攔截所有目標類方法的調用,obj 表示目標類的實例,method 為目標類方法的反射對象,args 為方法的動態入參,methodProxy 為代理類實例。method.invoke(targetObject, args) 通過代理類調用父類中的方法。

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 
 }

結果如下:

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

4. 總結

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

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

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

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-08-25發表,共計4999字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 荃湾区| 额济纳旗| 临沧市| 崇阳县| 九寨沟县| 怀来县| 偃师市| 汕头市| 远安县| 休宁县| 顺昌县| 凉城县| 巴中市| 全南县| 邢台市| 从化市| 闸北区| 怀来县| 磐安县| 陇西县| 彭泽县| 长沙市| 正安县| 太原市| 马山县| 望谟县| 岚皋县| 抚顺县| 福州市| 云梦县| 夏津县| 麻江县| 江油市| 永仁县| 仁寿县| 淄博市| 上虞市| 高阳县| 赤水市| 逊克县| 杭锦旗|