Spring-AOP源码分析随手记(二)

这次来分析下切面的执行过程。

1.怎么看?

怎么开始看源码呢?就直接从被增强的方法调用那里打断点,看看怎么执行的:

然后就来到了这:

2.初步分析

里面有段:

if (this.advised.exposeProxy) {
   // Make invocation available if necessary.
   oldProxy = AopContext.setCurrentProxy(proxy);
   setProxyContext = true;
}

就是上篇文章讲到的注解配置暴露代理对象,放到AopContext的ThreadLocal里去,之后就可以随时用 AopContext.currentProxy())取到代理对象。

接下来有段重要的:

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

获取拦截器链,就是把这次相关的增强器转化成拦截器获取出来

然后:

if (chain.isEmpty()) {
   // We can skip creating a MethodInvocation: just invoke the target directly
   // Note that the final invoker must be an InvokerInterceptor so we know it does
   // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
   Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
   retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
   // We need to create a method invocation...
   invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
   // Proceed to the joinpoint through the interceptor chain.
   retVal = invocation.proceed();
}

这里就是判断拦截器链有没有东西,如果是空的就直接通过反射调用,不是空就进行else逻辑了,那else是重点了,即invocation.proceed();

3.invocation.proceed()

public Object proceed() throws Throwable {
   // We start with an index of -1 and increment early.
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
   }

   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      // Evaluate dynamic method matcher here: static part will already have
      // been evaluated and found to match.
      InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
         return dm.interceptor.invoke(this);
      }
      else {
         // Dynamic matching failed.
         // Skip this interceptor and invoke the next in the chain.
         return proceed();
      }
   }
   else {
      // It's an interceptor, so we just invoke it: The pointcut will have
      // been evaluated statically before this object was constructed.
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

第一个if是递归的终止条件,明显是根据下标进行终止的条件

后面进行前++,又调用了

((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);

然而这里面是:

public Object invoke(MethodInvocation mi) throws Throwable {
   MethodInvocation oldInvocation = invocation.get();
   invocation.set(mi);
   try {
      return mi.proceed();
   }
   finally {
      invocation.set(oldInvocation);
   }
}

又跑回proceed方法去了,递归。

第二次来到的时候下标就是0了(第一次是-1,默认的),前++为1的下标的话,取出来的东西继续调用invoke发现进的是AspectJAfterThrowingAdvice的invoke了(第一次是ExposeInvocationInterceptor的invoke,记录下MethodInvocation供后面执行链获取)

这个AspectJAfterThrowingAdvice的invoke的源码如下(不一样):

public Object invoke(MethodInvocation mi) throws Throwable {
   try {
      return mi.proceed();
   }
   catch (Throwable ex) {
      if (shouldInvokeOnThrowing(ex)) {
         invokeAdviceMethod(getJoinPointMatch(), null, ex);
      }
      throw ex;
   }
}

继续递归,不过这次把调用链try起来了,出异常就走异常增强通知invokeAdviceMethod

继续debug,又是递归到invoke,但这次是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到了后置通知AspectJAfterAdvice类的invoke:

public Object invoke(MethodInvocation mi) throws Throwable {
   try {
      return mi.proceed();
   }
   finally {
      invokeAdviceMethod(getJoinPointMatch(), null, null);
   }
}

看到没,后置通知类的invokeAdviceMethod调用是用的finally,所以后置通知始终执行!

继续递归

跳到了前置通知类MethodBeforeAdviceInterceptor的invoke

public Object invoke(MethodInvocation mi) throws Throwable {
   this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
   return mi.proceed();
}

注意这里不一样了!它是先调用自己再调执行链,这也就是为什么前置通知早于方法执行

before方法执行完之后,进proceed了,递归即将结束:

所有的增强器取出来了,并执行了before 这里递归就结束了,调用目标方法:invokeJoinpoint

然后是后置通知各种,有异常就走之前try finally那里。

至此aop具体逻辑结束!

总结下易翻车点:

1.注意看自己的源码是哪个类,不然很懵逼,因为调了很多个类的同名方法invoke。

2.注意看是递归,和递归结束条件

3.注意invoke的实现,对于不同的增强器的逻辑是不一样的

4.增强器那个集合是有顺序好的

原文地址:https://www.cnblogs.com/chz-blogs/p/12006222.html

时间: 2024-10-10 23:50:16

Spring-AOP源码分析随手记(二)的相关文章

曹工说Spring Boot源码(18)-- Spring AOP源码分析三部曲,终于快讲完了 (aop:config完整解析【下】)

写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean Definition到底是什么,附spring思维导图分享 曹工说Spring Boot源码(2)-- Bean Definition到底是什么,咱们对着接口,逐个方法讲解 曹工说Spring Boot源码(3)-- 手动注册Bean Definition不比游戏好玩吗,我们来试一下 曹工说Spring Boot源码(4)-- 我是怎么自定义ApplicationContext,从json文件读取bean de

Spring AOP源码分析(拦截器调用的实现)

在Spring AOP通过JDK或者Cglib的方式生成代理对象的时候,相关的拦截器已经配置到代理对象中去了,拦截器在代理对象中的作用是通过对这些方法的回调完成的. JdkDynamicAopProxy的invoke拦截 JdkDynamicAopProxy的invoke @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { MethodInvocation in

Spring AOP源码分析

AOP基本概述 Advice(通知) BeforeAdvice package org.springframework.aop; import java.lang.reflect.Method; public interface MethodBeforeAdvice extends BeforeAdvice { void before(Method method, Object[] args, Object target) throws Throwable; } before是回调方法,在Adv

spring事务源码分析结合mybatis源码(一)

最近想提升,苦逼程序猿,想了想还是拿最熟悉,之前也一直想看但没看的spring源码来看吧,正好最近在弄事务这部分的东西,就看了下,同时写下随笔记录下,以备后查. spring tx源码分析 这里只分析简单事务也就是DataSourceTransactionManager 首先肯定找入口了,看过spring源码的同学一定都会找spring tx的入口就是在TxAdviceBeanDefinitionParser这里将解析tx的配置,生成TransactionInterceptor对象,这个也就是一

Spring IoC 源码分析 (基于注解) 之 包扫描

在上篇文章Spring IoC 源码分析 (基于注解) 一我们分析到,我们通过AnnotationConfigApplicationContext类传入一个包路径启动Spring之后,会首先初始化包扫描的过滤规则.那我们今天就来看下包扫描的具体过程. 还是先看下面的代码: AnnotationConfigApplicationContext类 //该构造函数会自动扫描以给定的包及其子包下的所有类,并自动识别所有的Spring Bean,将其注册到容器中 public AnnotationConf

Spring AMQP 源码分析 05 - 异常处理

### 准备 ## 目标 了解 Spring AMQP Message Listener 如何处理异常 ## 前置知识 <Spring AMQP 源码分析 04 - MessageListener> ## 相关资源 Offical doc:<http://docs.spring.io/spring-amqp/docs/1.7.3.RELEASE/reference/html/_reference.html#exception-handling> Sample code:<ht

Spring AMQP 源码分析 07 - MessageListenerAdapter

### 准备 ## 目标 了解 Spring AMQP 如何用 POJO 处理消息 ## 前置知识 <Spring AMQP 源码分析 04 - MessageListener> ## 相关资源 Offical doc:<http://docs.spring.io/spring-amqp/docs/1.7.3.RELEASE/reference/html/_reference.html#message-listener-adapter> Sample code:<https:

Spring AMQP 源码分析 06 - 手动消息确认

### 准备 ## 目标 了解 Spring AMQP 如何手动确认消息已成功消费 ## 前置知识 <Spring AMQP 源码分析 04 - MessageListener> ## 相关资源 Offical doc:<http://docs.spring.io/spring-amqp/docs/1.7.3.RELEASE/reference/html/_reference.html#message-listener-adapter> Sample code:<https:

Spring AMQP 源码分析 08 - XML 配置

### 准备 ## 目标 通过 XML 配置文件使用 Spring AMQP ## 前置知识 <Spring AMQP 源码分析 07 - MessageListenerAdapter> ## 相关资源 Sample code:<https://github.com/gordonklg/study>,rabbitmq module 源码版本:Spring AMQP 1.7.3.RELEASE ## 测试代码 gordon.study.rabbitmq.springamqp.XmlC