天天看點

一文帶你搞懂從動态代理實作到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生成類過程低效問題)。

下面我們分别來示例實作這兩種方法。

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

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

結果如下:

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

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

上述實作了建立子類的方法與代理的方法。getProxy(SuperClass.class)方法通過入參即父類的位元組碼,擴充父類的class來建立代理對象。intercept()方法攔截所有目标類方法的調用,obj表示目标類的執行個體,method為目标類方法的反射對象,args為方法的動态入參,methodProxy為代理類執行個體。method.invoke(targetObject, args)通過代理類調用父類中的方法。

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

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

jdk動态代理代理與cglib代理原理探究

AOP的底層實作-CGLIB動态代理和JDK動态代理

本文分享自華為雲社群《還不懂Spring AOP?一文帶你搞懂動态代理》,原文作者:aoho 。

點選關注,第一時間了解華為雲新鮮技術~

繼續閱讀