前情回顧:
在上一篇中,通過 wrapIfNecessary 方法,我們獲取到了合適的增強器(日志方法)與業務
類進行包裝,最終返回了我們業務類的代理對象。
![]()
本篇我們將從業務方法的執行開始,看看增強器(日志方法)是怎么在方法執行的前后和發
生異常時被調用的。以及在文章的最后總結整個AOP的執行流程。
1、調試的起點:
給測試方法打上斷點,然后一直跳到下一個斷點直到執行方法,如下

接着進入方法,會被intercept方法攔截
進入斷點:
1 @Override 2 public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { 3 Object oldProxy = null; 4 boolean setProxyContext = false; 5 Class<?> targetClass = null; 6 Object target = null; 7 try { 8 if (this.advised.exposeProxy) { 9 // Make invocation available if necessary.
10 oldProxy = AopContext.setCurrentProxy(proxy); 11 setProxyContext = true; 12 } 13 // May be null. Get as late as possible to minimize the time we 14 // "own" the target, in case it comes from a pool...
15 target = getTarget(); 16 if (target != null) { 17 targetClass = target.getClass(); 18 } 19 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 20 Object retVal; 21 // Check whether we only have one InvokerInterceptor: that is, 22 // no real advice, but just reflective invocation of the target.
23 if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { 24 // We can skip creating a MethodInvocation: just invoke the target directly. 25 // Note that the final invoker must be an InvokerInterceptor, so we know 26 // it does nothing but a reflective operation on the target, and no hot 27 // swapping or fancy proxying.
28 Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); 29 retVal = methodProxy.invoke(target, argsToUse); 30 } 31 else { 32 // We need to create a method invocation...
33 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); 34 } 35 retVal = processReturnType(proxy, target, method, retVal); 36 return retVal; 37 } 38 finally { 39 if (target != null) { 40 releaseTarget(target); 41 } 42 if (setProxyContext) { 43 // Restore old proxy.
44 AopContext.setCurrentProxy(oldProxy); 45 } 46 } 47 }
intercept 方法從上往下看:
16~18:獲取目標類(注意不是代理對象)
![]()
19:通過目標類和目標方法獲取攔截器鏈
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
2、重點探究獲取攔截器鏈的過程
進入 getInterceptorsAndDynamicInterceptionAdvice

繼續進入 this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass)
1 @Override 2 public List<Object> getInterceptorsAndDynamicInterceptionAdvice( 3 Advised config, Method method, Class<?> targetClass) { 4
5 // This is somewhat tricky... We have to process introductions first, 6 // but we need to preserve order in the ultimate list.
7 List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length); 8 Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); 9 boolean hasIntroductions = hasMatchingIntroductions(config, actualClass); 10 AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); 11
12 for (Advisor advisor : config.getAdvisors()) { 13 if (advisor instanceof PointcutAdvisor) { 14 // Add it conditionally.
15 PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; 16 if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { 17 MethodInterceptor[] interceptors = registry.getInterceptors(advisor); 18 MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); 19 if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) { 20 if (mm.isRuntime()) { 21 // Creating a new object instance in the getInterceptors() method 22 // isn't a problem as we normally cache created chains.
23 for (MethodInterceptor interceptor : interceptors) { 24 interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); 25 } 26 } 27 else { 28 interceptorList.addAll(Arrays.asList(interceptors)); 29 } 30 } 31 } 32 } 33 else if (advisor instanceof IntroductionAdvisor) { 34 IntroductionAdvisor ia = (IntroductionAdvisor) advisor; 35 if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) { 36 Interceptor[] interceptors = registry.getInterceptors(advisor); 37 interceptorList.addAll(Arrays.asList(interceptors)); 38 } 39 } 40 else { 41 Interceptor[] interceptors = registry.getInterceptors(advisor); 42 interceptorList.addAll(Arrays.asList(interceptors)); 43 } 44 } 45
46 return interceptorList; 47 }
以上代碼從上往下看:
5:創建攔截器鏈
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length)
12~32:
- 遍歷所有增強器
- 經過一系列判斷,將增強器放入interceptorList中 :
- interceptorList.addAll(Arrays.asList(interceptors))
46:將攔截器鏈返回
接下來將攔截器鏈返回,並存入緩存中

最后將攔截器鏈返回

這就是攔截器鏈獲取的過程
接下來來到 intercept 方法的真正執行部分:
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
通過new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy) 獲取到方法攔截器鏈
一進來先調用父類方法:

設置好代理對象、目標類、目標方法、攔截器鏈等一系列屬性:

接着一路返回后調用 proceed 方法進行執行:
1 @Override 2 public Object proceed() throws Throwable { 3 // We start with an index of -1 and increment early.
4 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { 5 return invokeJoinpoint(); 6 } 7
8 Object interceptorOrInterceptionAdvice =
9 this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); 10 if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { 11 // Evaluate dynamic method matcher here: static part will already have 12 // been evaluated and found to match.
13 InterceptorAndDynamicMethodMatcher dm =
14 (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; 15 if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) { 16 return dm.interceptor.invoke(this); 17 } 18 else { 19 // Dynamic matching failed. 20 // Skip this interceptor and invoke the next in the chain.
21 return proceed(); 22 } 23 } 24 else { 25 // It's an interceptor, so we just invoke it: The pointcut will have 26 // been evaluated statically before this object was constructed.
27 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); 28 } 29 }
3~6:可以看到有一個從-1開始的索引,這是用來記錄當前執行次數的(這里的size為5對應我們的五個增強器)

8~9:每次從攔截器鏈中獲取一個增強器,索引加一
10:判斷這個增強器是不是 InterceptorAndDynamicMethodMatcher 類型,我們這里判斷不滿足,來到了else,返回調用 invoke 方法的結果

接下來我們進入這個執行過程
invoke方法調用proceed方法

來到proceed方法繼續判斷索引大小

往下走又來到 invoke 方法,從下圖可以看到當前是異常增強器的invoke()

進入invoke
先 return 調用 proceed 方法
可以看到下圖中 catch 部分,說明如果有出現異常,會在catch部分調用增強器方法,並拋出異常

接下來又是調用AfterReturning的invoke過程

下圖可以看到又調用了proceed

中間的過程也一樣,這里就不演示了
最終我們的索引來到末尾
整個過程開始從內到外執行日志方法
開始調用日志方法打印:

拋出異常

最終攔截器鏈調用完畢,得到結果:

以上可以看到,整個執行流程是一個遞歸調用的過程,對之前排好序的攔截器鏈,通過索引判斷界限,一層一層往里調用,最終遞歸回來一層層執行增強器(日志方法)

3、AOP總結:
通過@EnableAspectJAutoProxy 注解,給容器中注冊 AnnotationAwareAspectJAutoProxyCreator,這個組件實際上是一個后置處理器,
這樣在容器創建過程,也就是refresh過程中,對后置處理器進行注冊調用
掃描獲取到目標代理對象的類和切面類,將目標代理對象和切面方法包裝成增強器
最后得到一系列增強器,創建與目標代理對象同名的代理類並注冊進容器
在以后,使用的就是同名的代理類,並通過攔截器鏈來攔截並執行切面方法,從而達到切面方法的效果
這里對目標代理類的代理利用了代理模式的設計思想,即將目標類和增強器都包裝起來(目標類和增強器包裝在代理類的advised屬性中)
而代理類中的增強器則使用了適配器的設計思想(使得目標類和切面類能夠一起工作)
AOP uml圖
以下UML圖是我對AOP的理解,如果有不對之處,歡迎大家指出


