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

 

 

 

 

 

 

 

 

 

posted @ 2020-03-08 16:03  就像空中月  阅读(863)  评论(1编辑  收藏  举报