Spring——AOP原理及源码五【系列完】


前情回顾:

  上一篇中,通过 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


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

 

以上代码从上往下看:

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

 

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的理解,如果有不对之处,欢迎大家指出

 

 

 

 

 

 

 

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM