您好,登錄后才能下訂單哦!
如何從動態代理實現到Spring AOP,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
小編主要講了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來實現的。總的來說,反射機制在生成類的過程中比較高效,而asm在生成類之后的相關執行過程中比較高效(可以通過將asm生成的類進行緩存,這樣解決asm生成類過程低效問題)。
下面我們分別來示例實現這兩種方法。
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"; } }
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方法委派前判斷權限,實現方法的攔截。
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----
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"; } }
該類的實現和上面的接口實現一樣,為了保持統一。
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)通過代理類調用父類中的方法。
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----
主要講了Spring Aop動態代理實現的兩種方式,并分別介紹了其優缺點。jdk動態代理的應用前提是目標類基于統一的接口。如果沒有該前提,jdk動態代理不能應用。由此可以看出,jdk動態代理有一定的局限性,cglib這種第三方類庫實現的動態代理應用更加廣泛,且在效率上更有優勢。
JDK動態代理機制是委托機制,不需要以來第三方的庫,只要要JDK環境就可以進行代理,動態實現接口類,在動態生成的實現類里面委托為hanlder去調用原始實現類方法;CGLib 必須依賴于CGLib的類庫,使用的是繼承機制,是被代理類和代理類繼承的關系,所以代理類是可以賦值給被代理類的,如果被代理類有接口,那么代理類也可以賦值給接口。
關于如何從動態代理實現到Spring AOP問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。