javascript
关于Spring AOP,除了动态代理、CGLIB,你还知道什么?
來源 |?草捏子
責編 | Carol
封圖?| CSDN 付費下載于視覺中國
Spring 作為 Java 中最流行的框架,主要歸功于其提供的 IOC 和 AOP 功能。本文將討論 Spring AOP 的實現。第一節將介紹 AOP 的相關概念,若熟悉可跳過,第二節中結合源碼介紹 Spring 是如何實現 AOP 的各概念。
AOP概念
1.1 JoinPoint
進行織入操作的程序執行點。
常見類型:
方法調用(Method Call):某個方法被調用的時點。
方法調用執行(Method Call Execution):某個方法內部開始執行的時點。
方法調用是在調用對象上的執行點,方法調用執行是在被調用對象的方法開始執行點。
構造方法調用(Constructor Call):對某個對象調用其構造方法的時點。
構造方法執行(Constructor Call Execution):某個對象構造方法內部開始執行的時點。
字段設置(Field Set):某個字段通過 setter 方法被設置或直接被設置的時點。
字段獲取(Field Get):某個字段通過 getter 方法被訪問或直接被訪問的時點。
異常處理執行(Exception Handler Execution):某些類型異常拋出后,異常處理邏輯執行的時點。
類初始化(Class Initialization):類中某些靜態類型或靜態塊的初始化時點。
1.2 Pointcut
Jointpoint 的表述方式。
常見表述方式:
直接指定 Joinpoint 所在方法名稱
正則表達式
特定的 Pointcut 表述語言
1.3 Advice
單一橫切關注點邏輯的載體,織入到 Joinpoint 的橫切邏輯。
具體形式:
Before Advice:Joinpoint 處之前執行。
After Advice:Joinpoint 處之后執行,細分為三種:
After Returning Advice:Joinpoint 處正常完成后執行。
After Throwing Advice:Joinpoint 處拋出異常后執行。
After Finally Advice:Joinpoint 處正常完成或拋出異常后執行。
Around Advice:包裹 Joinpoint,在 Joinpoint 之前和之后執行,具有 Before Advice 和 After Advice 的功能。
Introduction:為原有的對象添加新的屬性或行為。
1.4 Aspect
對橫切關注點邏輯進行模塊化封裝的 AOP 概念實體,包含多個 Pointcut 和相關 Advice 的定義。
1.5 織入和織入器
織入:將 Aspect 模塊化的橫切關注點集成到 OOP 系統中。
織入器:用于完成織入操作。
1.6 Target
在織入過程中被織入橫切邏輯的對象。
將上述 6 個概念放在一塊,如下圖所示:
AOP各個概念所處的場景
在了解 AOP 的各種概念后,下面將介紹 Spring 中 AOP 概念的具體實現。
Spring 中的實現
前文提到 AOP 的 Joinpoint 有多種類型,方法調用、方法執行、字段設置、字段獲取等。而在 Spring AOP 中,僅支持方法執行類型的 Joinpoint,但這樣已經能滿足 80% 的開發需要,如果有特殊需求,可求助其他 AOP 產品,如 AspectJ。由于 Joinpoint 涉及運行時的過程,相當于組裝好所有部件讓 AOP 跑起來的最后一步。所以將介紹完其他概念實現后,最后介紹 Joinpoint 的實現。
2.1 Pointcut
由于 Spring AOP 僅支持方法執行類別的 Joinpoint,因此 Pointcut 需要定義被織入的方法,又因為 Java 中方法封裝在類中,所以 Pointcut 需要定義被織入的類和方法,下面看其實現。
Spring 用?org.springframework.aop.Pointcut?接口定義 Pointcut 的頂層抽象。
public?interface?Pointcut?{//?ClassFilter用于匹配被織入的類???ClassFilter?getClassFilter();//?MethodMatcher用于匹配被織入的方法MethodMatcher?getMethodMatcher();//?TruePoincut的單例對象,默認匹配所有類和方法Pointcut?TRUE?=?TruePointcut.INSTANCE; }我們可以看出,Pointcut?通過?ClassFilter?和?MethodMatcher?的組合來定義相應的 Joinpoint。Pointcut?將類和方法拆開來定義,是為了能夠重用。例如有兩個 Joinpoint,分別是 A 類的?fun()?方法和 B 類的?fun()?方法,兩個方法簽名相同,則只需一個?fun()?方法的?MethodMatcher?對象,達到了重用的目的,ClassFilter?同理。
下面了解下?ClassFilter?和?MethodMatcher如何進行匹配。
ClassFilter?使用matches方法匹配被織入的類,定義如下:
public?interface?ClassFilter?{//?匹配被織入的類,匹配成功返回true,失敗返回falseboolean?matches(Class<?>?clazz);//?TrueClassFilter的單例對象,默認匹配所有類ClassFilter?TRUE?=?TrueClassFilter.INSTANCE; }MethodMatcher?也是使用?matches方法?匹配被織入的方法,定義如下:
public?interface?MethodMatcher?{//?匹配被織入的方法,匹配成功返回true,失敗返回false//?不考慮具體方法參數boolean?matches(Method?method,?Class<?>?targetClass);//?匹配被織入的方法,匹配成功返回true,失敗返回false//?考慮具體方法參數,對參數進行匹配檢查boolean?matches(Method?method,?Class<?>?targetClass,?Object...?args);//?一個標志方法//?false表示不考慮參數,使用第一個matches方法匹配//?true表示考慮參數,使用第二個matches方法匹配boolean?isRuntime();//?TrueMethodMatcher的單例對象,默認匹配所有方法MethodMatcher?TRUE?=?TrueMethodMatcher.INSTANCE;}看到?matches?方法的聲明,你是否會覺得有點奇怪,在?ClassFilter?中不是已經對類進行匹配了嗎,那為什么在?MethodMatcher?的?matches?方法中還有一個?Class<?> targetClass?參數。請注意,這里的?Class<?>?類型參數將不會進行匹配,而僅是為了找到具體的方法。例如:
public?boolean?matches(Method?method,?Class<?>?targetClass)?{Method?targetMethod?=?AopUtils.getMostSpecificMethod(method,?targetClass);// ... }在MethodMatcher相比ClassFilter特殊在有兩個?matches?方法。將根據?isRuntime()?的返回結果決定調用哪個。而MethodMatcher因isRuntime()分為兩個抽象類?StaticMethodMatcher(返回false,不考慮參數)和?DynamicMethodMatcher(返回true,考慮參數)。
Pointcut?也因?MethodMathcer?可分為?StaticMethodMatcherPointcut?和?DynamicMethodMatcherPointcut,相關類圖如下所示:
Pointcut相關類圖
DynamicMethodMatcherPointcut?本文將不介紹,主要介紹下類圖中列出的三個實現類。
(1)NameMatchMethodPointcut
通過指定方法名稱,然后與方法的名稱直接進行匹配,還支持 “*” 通配符。
public?class?NameMatchMethodPointcut?extends?StaticMethodMatcherPointcut?implements?Serializable?{//?方法名稱private?List<String>?mappedNames?=?new?ArrayList<>();//?設置方法名稱public?void?setMappedNames(String...?mappedNames)?{this.mappedNames?=?new?ArrayList<>(Arrays.asList(mappedNames));}@Overridepublic?boolean?matches(Method?method,?Class<?>?targetClass)?{for?(String?mappedName?:?this.mappedNames)?{//?根據方法名匹配,isMatch提供“*”通配符支持if?(mappedName.equals(method.getName())?||?isMatch(method.getName(),?mappedName))?{return?true;}}return?false;}//?... }(2)JdkRegexpMethodPointcut
內部有一個 Pattern 數組,通過指定正則表達式,然后和方法名稱進行匹配。
(3)AnnotationMatchingPointcut
根據目標對象是否存在指定類型的注解進行匹配。
2.2 Advice
Advice 為橫切邏輯的載體,Spring AOP 中關于 Advice 的接口類圖如下所示:
Advice相關類圖
(1)MethodBeforeAdvice
橫切邏輯將在?Joinpoint 方法之前執行。可用于進行資源初始化或準備性工作。
public?interface?MethodBeforeAdvice?extends?BeforeAdvice?{void?before(Method?method,?Object[]?args,?@Nullable?Object?target)?throws?Throwable;}下面來實現一個?MethodBeforeAdvice,看下其效果。
public?class?PrepareResourceBeforeAdvice?implements?MethodBeforeAdvice?{@Overridepublic?void?before(Method?method,?Object[]?args,?Object?target)?throws?Throwable?{System.out.println("準備資源");}}定義一個?ITask?接口:
public?interface?ITask?{void?execute();}ITask?的實現類?MockTask:
public?class?MockTask?implements?ITask?{@Overridepublic?void?execute()?{System.out.println("開始執行任務");System.out.println("任務完成");}}Main 方法如下,ProxyFactory、Advisor?在后續會進行介紹,先簡單了解下,通過ProxyFactory拿到代理類,Advisor用于封裝?Pointcut?和?Advice。
public?class?Main?{public?static?void?main(String[]?args)?{MockTask?task?=?new?MockTask();ProxyFactory?weaver?=?new?ProxyFactory(task);weaver.setInterfaces(new?Class[]{ITask.class});//?內含一個NameMatchMethodPointcutNameMatchMethodPointcutAdvisor?advisor?=?new?NameMatchMethodPointcutAdvisor();//?指定NameMatchMethodPointcut的方法名advisor.setMappedName("execute");//?指定Adviceadvisor.setAdvice(new?PrepareResourceBeforeAdvice());weaver.addAdvisor(advisor);ITask?proxyObject?=?(ITask)?weaver.getProxy();proxyObject.execute();}}/**?output: 準備資源 開始執行任務 任務完成 **/可以看出在執行代理對象?proxyObject?的?execute?方法時,先執行了?PrepareResourceBeforeAdvice?中的?before?方法。
(2)ThrowsAdvice
橫切邏輯將在?Joinpoint 方法拋出異常時執行。可用于進行異常監控工作。
ThrowsAdvice 接口未定義任何方法,但約定在實現該接口時,定義的方法需符合如下規則:
void?afterThrowing([Method,?args,?target],?ThrowableSubclass)前三個參數為 Joinpoint 的相關信息,可省略。ThrowableSubclass?指定需要攔截的異常類型。
例如可定義多個?afterThrowing?方法捕獲異常:
public?class?ExceptionMonitorThrowsAdvice?implements?ThrowsAdvice?{public?void?afterThrowing(Throwable?t)?{System.out.println("發生【普通異常】");}public?void?afterThrowing(RuntimeException?e)?{System.out.println("發生【運行時異常】");}public?void?afterThrowing(Method?m,?Object[]?args,?Object?target,?ApplicationException?e)?{System.out.println(target.getClass()?+?m.getName()?+?"發生【應用異常】");}}修改下?MockTask?的內容:
public?class?MockTask?implements?ITask?{@Overridepublic?void?execute()?{System.out.println("開始執行任務");//?拋出一個自定義的應用異常throw?new?ApplicationException();//?System.out.println("任務完成");}}修改下?Main?的內容:
public?class?Main?{public?static?void?main(String[]?args)?{MockTask?task?=?new?MockTask();ProxyFactory?weaver?=?new?ProxyFactory(task);weaver.setInterfaces(new?Class[]{ITask.class});NameMatchMethodPointcutAdvisor?advisor?=?new?NameMatchMethodPointcutAdvisor();advisor.setMappedName("execute");//?指定異常監控Adviceadvisor.setAdvice(new?ExceptionMonitorThrowsAdvice());weaver.addAdvisor(advisor);ITask?proxyObject?=?(ITask)?weaver.getProxy();proxyObject.execute();}}/**?output: 開始執行任務 class?com.chaycao.spring.aop.MockTaskexecute發生【應用異常】 **/當拋出?ApplicationException?時,被相應的?afterThrowing?方法捕獲到。
(3)AfterReturningAdvice
橫切邏輯將在?Joinpoint 方法正常返回時執行。可用于處理資源清理工作。
public?interface?AfterReturningAdvice?extends?AfterAdvice?{void?afterReturning(@Nullable?Object?returnValue,?Method?method,?Object[]?args,?@Nullable?Object?target)?throws?Throwable;}實現一個資源清理的 Advice :
public?class?ResourceCleanAfterReturningAdvice?implements?AfterReturningAdvice?{@Overridepublic?void?afterReturning(Object?returnValue,?Method?method,?Object[]?args,?Object?target)?throws?Throwable?{System.out.println("資源清理");}}修改?MockTask?為正常執行成功, 修改?Main?方法為指定?ResourceCLeanAfterReturningAdvice,效果如下:
/**?output: 開始執行任務 任務完成 資源清理 **/(4)MethodInterceptor
相當于 Around Advice,功能十分強大,可在 Joinpoint 方法前后執行,甚至修改返回值。其定義如下:
public?interface?MethodInterceptor?extends?Interceptor?{Object?invoke(MethodInvocation?invocation)?throws?Throwable;}MethodInvocation?是對?Method?的封裝,通過?proceed()?對方法進行調用。下面舉個例子:
public?class?AroundMethodInterceptor?implements?MethodInterceptor?{@Overridepublic?Object?invoke(MethodInvocation?invocation)?throws?Throwable?{System.out.println("準備資源");try?{return?invocation.proceed();}?catch?(Exception?e)?{System.out.println("監控異常");return?null;}?finally?{System.out.println("資源清理");}}}上面實現的 invoke 方法,一下子把前面說的三種功能都實現了。
以上 4 種 Advice 會在目標對象類的所有實例上生效,被稱為 per-class 類型的 Advice。還有一種 per-instance 類型的 Advice,可為實例添加新的屬性或行為,也就是第一節提到的 Introduction。
(5)Introduction
Spring 為目標對象添加新的屬性或行為,需要聲明接口和其實現類,然后通過攔截器將接口的定義和實現類的實現織入到目標對象中。我們認識下?DelegatingIntroductionInterceptor,其作為攔截器,當調用新行為時,會委派(delegate)給實現類來完成。
例如,想在原?MockTask?上進行加強,但不修改類的聲明,可聲明一個新的接口?IReinfore:
public?interface?IReinforce?{String?name?=?"增強器";void?fun(); }再聲明一個接口的實現類:
public?class?ReinforeImpl?implements?IReinforce?{@Overridepublic?void?fun()?{System.out.println("我變強了,能執行fun方法了");}}修改下 Main 方法:
public?class?Main?{public?static?void?main(String[]?args)?{MockTask?task?=?new?MockTask();ProxyFactory?weaver?=?new?ProxyFactory(task);weaver.setInterfaces(new?Class[]{ITask.class});//?為攔截器指定需要委托的實現類的實例DelegatingIntroductionInterceptor?delegatingIntroductionInterceptor?=new?DelegatingIntroductionInterceptor(new?ReinforeImpl());weaver.addAdvice(delegatingIntroductionInterceptor);ITask?proxyObject?=?(ITask)?weaver.getProxy();proxyObject.execute();//?使用IReinfore接口調用新的屬性和行為IReinforce?reinforeProxyObject?=?(IReinforce)?weaver.getProxy();System.out.println("通過使用"?+?reinforeProxyObject.name);reinforeProxyObject.fun();}}/**?output: 開始執行任務 任務完成 通過使用增強器 我變強了,能執行fun方法了 **/代理對象?proxyObject?便通過攔截器,可以使用?ReinforeImpl?實現類的方法。
2.3 Aspect
Spring 中用?Advisor?表示 Aspect,不同之處在于?Advisor?通常只持有一個?Pointcut?和一個?Advice。Advisor?根據?Advice?分為?PointcutAdvisor?和?IntroductionAdvisor。
2.3.1 PointcutAdvisor
常用的?PointcutAdvisor?實現類有:
(1) DefaultPointcutAdvisor
最通用的實現類,可以指定任意類型的?Pointcut?和除了?Introduction?外的任意類型?Advice。
Pointcut?pointcut?=?...;?//?任意類型的Pointcut Advice?advice?=?...;?//?除了Introduction外的任意類型Advice DefaultPointcutAdvisor?advisor?=?new?DefaultPointcutAdvisor(); advisor.setPointcut(pointcut); advisor.setAdvice(advice);(2)NameMatchMethodPointcutAdvisor
在演示 Advice 的代碼中,已經有簡單介紹過,內部有一個?NameMatchMethodPointcut?的實例,可持有除?Introduction?外的任意類型?Advice。
Advice?advice?=?...;?//?除了Introduction外的任意類型Advice NameMatchMethodPointcutAdvisor?advisor?=?new?NameMatchMethodPointcutAdvisor(); advisor.setMappedName("execute"); advisor.setAdvice(advice);(3)RegexpMethodPointcutAdvisor
內部有一個?RegexpMethodPointcut?的實例。
2.3.2 IntroductionAdvisor
只能支持類級別的攔截,和?Introduction?類型的?Advice。實現類有?DefaultIntroductionAdvisor。
DelegatingIntroductionInterceptor?introductionInterceptor?=new?DelegatingIntroductionInterceptor(new?ReinforeImpl());DefaultIntroductionAdvisor?advisor?=?new?DefaultIntroductionAdvisor(introductionInterceptor,?IReinforce.class);2.4 織入和織入器
在演示 Advice 的代碼中,我們使用?ProxyFactory?作為織入器
MockTask?task?=?new?MockTask(); //?織入器 ProxyFactory?weaver?=?new?ProxyFactory(task); weaver.setInterfaces(new?Class[]{ITask.class}); NameMatchMethodPointcutAdvisor?advisor?=?new?NameMatchMethodPointcutAdvisor(); advisor.setMappedName("execute"); advisor.setAdvice(new?PrepareResourceBeforeAdvice()); weaver.addAdvisor(advisor); //?織入,返回代理對象 ITask?proxyObject?=?(ITask)?weaver.getProxy(); proxyObject.execute();ProxyFactory?生成代理對象方式有:
如果目標類實現了某些接口,默認通過動態代理生成。
如果目標類沒有實現接口,默認通過CGLIB生成。
也可以直接設置ProxyFactory生成的方式,即使實現了接口,也能使用CGLIB。
在之前的演示代碼中,我們沒有啟動 Spring 容器,也就是沒有使用 Spring IOC 功能,而是獨立使用了 Spring AOP。那么 Spring AOP 是如何與 Spring IOC 進行整合的?是采用了 Spring 整合最常用的方法 ——?FactoryBean。
ProxyFactoryBean?繼承了?ProxyFactory?的父類?ProxyCreatorSupport,具有了創建代理類的能力,同時實現了?FactoryBean?接口,當通過?getObject?方法獲得 Bean 時,將得到代理類。
2.5 Target
在之前的演示代碼中,我們直接為?ProxyFactory?指定一個對象為 Target。在?ProxyFactoryBean?中不僅能使用這種方式,還可以通過?TargetSource?的形式指定。
TargetSource?相當于為對象進行了一層封裝,ProxyFactoryBean?將通過?TargetSource?的?getTarget?方法來獲得目標對象。于是,我們可以通過?getTarget?方法來控制獲得的目標對象。TargetSource?的幾種實現類有:
(1)SingletonTargetSource
很簡單,內部只持有一個目標對象,直接返回。和我們直接指定對象的效果是一樣的。
(2)PrototypeTargetSource
每次將返回一個新的目標對象實例。
(3)HotSwappableTartgetSource
運行時,根據特定條件,動態替換目標對象類的具體實現。例如當一個數據源掛了,可以切換至另外一個。
(4)CommonsPool2TargetSource
返回有限數目的目標對象實例,類似一個對象池。
(5)ThreadLocalTargetSource
為不同線程調用提供不同目標對象
2.6 Joinpoint
終于到了最后的 Joinpoint,我們通過下面的示例來理解 Joinpoint 的工作機制。
MockTask?task?=?new?MockTask(); ProxyFactory?weaver?=?new?ProxyFactory(task); weaver.setInterfaces(new?Class[]{ITask.class}); PrepareResourceBeforeAdvice?beforeAdvice?=?new?PrepareResourceBeforeAdvice(); ResourceCleanAfterReturningAdvice?afterAdvice?=?new?ResourceCleanAfterReturningAdvice(); weaver.addAdvice(beforeAdvice); weaver.addAdvice(afterAdvice); ITask?proxyObject?=?(ITask)?weaver.getProxy(); proxyObject.execute();/**?output 準備資源 開始執行任務 任務完成 資源清理 **/我們知道?getProxy?會通過動態代理生成一個?ITask?的接口類,那么?execute?方法的內部是如何先執行了?beforeAdvice?的?before?方法,接著執行?task?的?execute方法,再執行?afterAdvice?的?after?方法呢?
答案就在生成的代理類中。在動態代理中,代理類方法調用的邏輯由?InvocationHandler?實例的?invoke?方法決定,那答案進一步鎖定在?invoke?方法。
在本示例中,ProxyFactory.getProxy??會調用 ?JdkDynamicAopProxy.getProxy??獲取代理類。
//?JdkDynamicAopProxy public?Object?getProxy(@Nullable?ClassLoader?classLoader)?{if?(logger.isTraceEnabled())?{logger.trace("Creating?JDK?dynamic?proxy:?"?+?this.advised.getTargetSource());}Class<?>[]?proxiedInterfaces?=?AopProxyUtils.completeProxiedInterfaces(this.advised,?true);findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);return?Proxy.newProxyInstance(classLoader,?proxiedInterfaces,?this); }在?getProxy?中為?newProxyInstance?的?InvocationHandler?參數傳入?this,即?JdkDynamicAopProxy?就是一個?InvocationHandler?的實現,其?invoke?方法如下:
//?JdkDynamicAopProxy public?Object?invoke(Object?proxy,?Method?method,?Object[]?args)?throws?Throwable?{//?通過advised(創建對象時初始化)獲得指定的advice//?會將advice用相應的MethodInterceptor封裝下List<Object>?chain?=?this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,?targetClass);if?(chain.isEmpty())?{Object[]?argsToUse?=?AopProxyUtils.adaptArgumentsIfNecessary(method,?args);retVal?=?AopUtils.invokeJoinpointUsingReflection(target,?method,?argsToUse);}else?{//?創建一個MethodInvocationMethodInvocation?invocation?=new?ReflectiveMethodInvocation(proxy,?target,?method,?args,?targetClass,?chain);//?調用procced,開始進入攔截鏈(執行目標對象方法和MethodInterceptor的advice)retVal?=?invocation.proceed();}return?retVal; }首先獲得指定的 advice,這里包含?beforeAdvice?和?afterAdvice?實例,但會用?MethodInterceptor?封裝一層,為了后面的攔截鏈。
再創建一個?RelectiveMethodInvocation?對象,最后通過?proceed?進入攔截鏈。
RelectiveMethodInvocation?就是 Spring AOP 中 Joinpoint 的一個實現,其類圖如下:
Joinpoint類圖
首先看下?RelectiveMethodInvocation?的構造函數:
protected?ReflectiveMethodInvocation(Object?proxy,?@Nullable?Object?target,?Method?method,?@Nullable?Object[]?arguments,@Nullable?Class<?>?targetClass,?List<Object>?interceptorsAndDynamicMethodMatchers)?{this.proxy?=?proxy;this.target?=?target;this.targetClass?=?targetClass;this.method?=?BridgeMethodResolver.findBridgedMethod(method);this.arguments?=?AopProxyUtils.adaptArgumentsIfNecessary(method,?arguments);this.interceptorsAndDynamicMethodMatchers?=?interceptorsAndDynamicMethodMatchers;}做了些相關屬性的賦值,然后看向?proceed?方法,如何調用目標對象和攔截器。
public?Object?proceed()?throws?Throwable?{//?currentInterceptorIndex從-1開始//?當達到已調用了所有的攔截器后,通過invokeJoinpoint調用目標對象的方法if?(this.currentInterceptorIndex?==?this.interceptorsAndDynamicMethodMatchers.size()?-?1)?{return?invokeJoinpoint();}//?獲得攔截器,調用其invoke方法//?currentInterceptorIndex加1Object?interceptorOrInterceptionAdvice?=this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);return?((MethodInterceptor)?interceptorOrInterceptionAdvice).invoke(this); }currentInterceptorIndex?從 -1 開始,interceptorsAndDynamicMethodMatchers里有兩個攔截器,再由于減 1,所有調用目標對象方法的條件是currentInterceptorIndex?等于 1。
首先由于?-1 != 1,會獲得包含了?beforeAdvice?的?MethodBeforeAdviceInterceptor?實例,?currentInterceptorIndex?加 1 變為 0。調用其?invoke?方法,由于是 Before-Advice,所以先執行?beforeAdvice?的?before?方法,然后調用?proceed?進入攔截鏈的下一環。
//?MethodBeforeAdviceInterceptor public?Object?invoke(MethodInvocation?mi)?throws?Throwable?{this.advice.before(mi.getMethod(),?mi.getArguments(),?mi.getThis());return?mi.proceed(); }又回到了?proceed?方法,0 != 1,再次獲得 advice,這次獲得的是包含?afterAdvice?的?AfterReturningAdviceInterceptor實例,?currentInterceptorIndex?加 1 變為 1。調用其?invoke?方法,由于是 After-Returning-Adivce,所以會先執行?proceed?進入攔截鏈的下一環。
//?AfterReturningAdviceInterceptor public?Object?invoke(MethodInvocation?mi)?throws?Throwable?{Object?retVal?=?mi.proceed();this.advice.afterReturning(retVal,?mi.getMethod(),?mi.getArguments(),?mi.getThis());return?retVal; }再次來到?proceed?方法,1 == 1,已調用完所有的攔截器,將執行目標對象的方法。然后 return 返回,回到?invoke?中,調用?afterAdvice?的?afterReturning。
所以在 Joinpoint 的實現中,通過?MethodInterceptor?完成了 目標對象方法和 Advice 的先后執行。
小結
在了解了 Spring AOP 的實現后,筆者對 AOP 的概念更加清晰了。在學習過程中最令筆者感興趣的是 Joinpoint 的攔截鏈,一開始不知道是怎么實現的,覺得很神奇 ???? 。最后學完了,總結下,好像也很簡單,通過攔截器的?invoke?方法和MethodInvocation.proceed?方法(進入下一個攔截器)的相互調用。
?
推薦閱讀
后端程序員必備:書寫高質量SQL的30條建議
螞蟻金服高要求的領域建模能力,對研發來說到底指什么?
Redis 6.0 新特性:多線程連環 13 問!
AI 修復 100 年前晚清影像喜提熱搜,有穿越內味兒了!
你現在從事的程序員還有多久會消失?牛津大學研究員幫你算了算
一次對語音技術的徹底批判
到底是哪些人在玩鏈游?| 《區塊鏈游戲玩家研究報告》
真香,朕在看了!
總結
以上是生活随笔為你收集整理的关于Spring AOP,除了动态代理、CGLIB,你还知道什么?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 云+X案例展 | 金融类:青云QingC
- 下一篇: 不少人暗搓搓的准备春招了,我有一些好东东