Spring AOP 源码执行流程

Spring AOP 源码执行流程

建议阅读AOP文章顺序:

首先说一声抱歉,本人Spring IOC源码没看过多少,所以,这里仅仅是 AOP 的主流程,(毕竟 AOP 的操作其实是嵌入在 IOC中,在Spring 注入bean的过程中,AOP 发挥的作用)

自己对AOP源码流程标注注释的仓库:仓库地址 基于spring 5.0.x

类功能介绍:1、都在源码的每个包的package.info中总结了,2、可以查看Spring AOP 类功能介绍 文章

这里用于测试 AOP源码流程的demo,用的是 Spring AOP应用 文章的案例


JDK代理和CGLIB代理之间的区别:

原生JDK代理:

  • 原生JDK代理是Java提供的一种动态代理方式,通过 java.lang.reflect.Proxy 类和接口实现;
  • JDK代理只能代理具体的类,即:实现接口的具体的类;
  • JDK代理在运行时通过反射机制动态生成代理类,代理类实现了被代理接口,并将方法调用委托给InvocationHandler处理器;
  • JDK代理要求被代理的类必须实现接口。

CGLIB代理:

  • CGLIB(Code Generation Library)是一个强大的第三方类库,可以在运行时生成字节码,创建代理对象。
  • CGLIB代理可以代理普通的类,不仅仅限于接口。
  • CGLIB代理通过继承的方式创建代理类,代理类继承了被代理类,并重写了被代理方法。
  • CGLIB代理不要求被代理的类实现接口。

在选择使用原生JDK代理还是CGLIB代理时,可以考虑以下因素:

  • 如果被代理的类是接口类型,并且不需要继承其他类,则可以选择原生JDK代理。
  • 如果被代理的类不是接口类型,或者需要继承其他类,则可以选择CGLIB代理。
  • 需要注意的是,CGLIB代理在生成代理类时会涉及到字节码操作,相比原生JDK代理会更加复杂和消耗更多的资源。因此,在性能要求较高的情况下,可以优先考虑原生JDK代理。

一、执行步骤

大致可以分为几步:(注解方式和配置文件方式)

  • 1、注册可以处理Spring AOP 注解方式的类到Spring IOC中;(配置文件spring.xml方式和注解方式的区别:就是往Spring IOC中注册解析AOP xml标签的过程)
    • 注解方式注册:AnnotationAwareAspectJAutoProxyCreator 类
    • 配置文件方式注册:AspectJAutoProxyBeanDefinitionParser类 这个只是解析xml配置文件节点,最后也是注册 AnnotationAwareAspectJAutoProxyCreator这个。
  • 2、构建 拦截器链(或者叫通知链),创建代理;并注册到beanFacatroy中。
  • 3、执行目标方法时,转为执行代理(就是当调用我们要增强的某个方法时,转而按切面配置的通知增强方式进行执行)。
  • 4、通知链的执行。

     整理了这份面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题

    需要全套面试笔记【点击此处】即可免费获取

二、注册

2.1 基于注解方式注册

 

java

复制代码

// 方式一: @Configuration @ComponentScan(basePackages = "aop") @EnableAspectJAutoProxy(proxyTargetClass = true) // 注解方式启动AOP public class AspectConfig { } // 方式二: 在不使用@EnableAspectJAutoProxy的时候, 在spring.xml中配置 <aop:aspectj-autoproxy proxy-target-class="false" expose-proxy="false"/> 我们可以点击一下aspectj-autoproxy,可以进入到 spring-aop.xsd中,查看该节点的source 用的也是 AnnotationAwareAspectJAutoProxyCreator // 注意:这两种方式,切面都是基于@AspectJ注解定义的。

通过 @EnableAspectJAutoProxy 这个注解我们可以找到在Spring 中只有一处是对该注解的处理:(该类是在 spring-context工程的org.springframework.context.annotation包中);这里就是入口了。

 

java

复制代码

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { /** * @param importingClassMetadata AspectJ切面的配置类,如:a-spring-test-pro 项目中的aop.aspect.AspectConfig切面配置 * @param registry 当前的 BeanDefinitionRegistry,将配置的 AspectJ注册到 registry * 入口: * 根据 @EnableAspectJAutoProxy的属性去注册,升级,配置AspectJ的自动代理对象创建者 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 1. 注册默认的 AnnotationAwareAspectJAutoProxyCreator 到 当前的registry中 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); // 2. 获取注解上的属性信息;这里获取的 @EnableAspectJAutoProxy上的 AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); // 3. 设置标签 if (enableAspectJAutoProxy != null) { // 3.1 获取并处理proxy-target-class属性: // false表示使用java原生动态代理; // true表示使用CGLib动态. // 但是对于一些没有接口实现的类来说,即使设置为false也会使用CGlib进行代理. if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } // 3.2 获取并处理expose-proxy标签,实现对于内部方法调用的AOP增强 if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } } }

先跟(1.)注册默认的 AnnotationAwareAspectJAutoProxyCreator 到 当前的registry中;一定要理解这句话,查看上面方法的参数试着理解。

 
 

java

复制代码

//1. 注册默认的 AnnotationAwareAspectJAutoProxyCreator 到 当前的registry中 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

就做一个件事,看看 register有没有注册AnnotationAwareAspectJAutoProxyCreator.class,如果有返回了 null,如果没有就new一个,注册。

主要就是进入到·AopConfigUtils#registerOrEscalateApcAsRequired()这个核心方法

 

java

复制代码

public abstract class AopConfigUtils { private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3); static { // Set up the escalation list... APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class); APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class); APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class); } // -> 来到这里 @Nullable public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) { return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null); } // --> 进入这个 /** * 注册默认的 AnnotationAwareAspectJAutoProxyCreator 到 当前的registry中 * @param registry 当前的BeanDefinitionRegistry * @param source * @return */ @Nullable public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary( BeanDefinitionRegistry registry, @Nullable Object source) { return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); } // ---> 核心处理方法 /** * 将 AnnotationAwareAspectJAutoProxyCreator(代理创建器(ProxyCreator))注册到当前的 registry中 * @param cls AnnotationAwareAspectJAutoProxyCreator * @param registry BeanDefinitionRegistry * @param source * @return */ @Nullable private static BeanDefinition registerOrEscalateApcAsRequired( Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); // 如果名为org.springframework.aop.config.internalAutoProxyCreator的bean已经注册 if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); //已经在册的ProxyCreator与当前期望的类型不一致,则依据优先级进行选择 if (!cls.getName().equals(apcDefinition.getBeanClassName())) { // 下面这两个方法findPriorityForClass()就是看看注册表registry中的key为AUTO_PROXY_CREATOR_BEAN_NAME的bean和 // 当前要注册 AnnotationAwareAspectJAutoProxyCreator 作比较。 // 比较 在 APC_PRIORITY_LIST 里面的三个类: // InfrastructureAdvisorAutoProxyCreator.class // AspectJAwareAdvisorAutoProxyCreator.class // AnnotationAwareAspectJAutoProxyCreator.class // 看一下那个索引下标index大,AnnotationAwareAspectJAutoProxyCreator的下标最大; // 目的就是为了注册 AnnotationAwareAspectJAutoProxyCreator int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); //选择优先级高的ProxyCreator更新注册 if (currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); } } return null; } // 如果注册表中没有对应的 ProxyCreator,就注册一个进去 cls是: // org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); // 这是优先级 @Order(1) 这个注解的所用,或者对应的优先级标签的登记,这里设置的默认值。 beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); // 注册进 ((DefaultListableBeanFactory) registry).beanDefinitionMap 中 // key : org.springframework.aop.config.internalAutoProxyCreator // value : AnnotationAwareAspectJAutoProxyCreator registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; } }

(2.) 获取注解上的属性信息;这里获取的 @EnableAspectJAutoProxy上的

 
 

java

复制代码

// 2. 获取注解上的属性信息;这里获取的 @EnableAspectJAutoProxy上的 AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);

这个没啥好介绍的,就是利用注解工具类,获取 @EnableAspectJAutoProxy上的的两个属性:proxyTargetClassexposeProxy

(3.)设置标签 proxyTargetClassexposeProxy

 
 

java

复制代码

// 3. 设置标签 if (enableAspectJAutoProxy != null) { // 3.1 获取并处理proxy-target-class属性: // false表示使用java原生动态代理; // true表示使用CGLib动态. // 但是对于一些没有接口实现的类来说,即使设置为false也会使用CGlib进行代理. if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } // 3.2 获取并处理expose-proxy标签,实现对于内部方法调用的AOP增强 if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } }

还是在AopConfigUtils类中;主要就两个方法:

AopConfigUtils#forceAutoProxyCreatorToUseClassProxying()AopConfigUtils#forceAutoProxyCreatorToExposeProxy()

可以以 proxyTargetClass属性为例,可以看到,先找前面注册AnnotationAwareAspectJAutoProxyCreator的BeanFactory,这里建议 debug 一下看看definition类型,找打里面 beanDefinitionMap属性,然后找到 AnnotationAwareAspectJAutoProxyCreator对应的 map 键值对,为其add属性,exposeProxy也一样。

 

java

复制代码

public abstract class AopConfigUtils { /** * 设置proxy-target-class属性为true. * false表示使用java原生动态代理; * true表示使用CGLib动态. * @param registry */ public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) { if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { // 这可以从 ((DefaultListableBeanFactory) registry).beanDefinitionMap 中, // 找到前面注册的Bean -> AnnotationAwareAspectJAutoProxyCreator BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); // 为其添加属性 proxyTargetClass,并置为 true definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE); } } /** * 设置 exposeProxy为true. * @param registry */ public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) { if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); definition.getPropertyValues().add("exposeProxy", Boolean.TRUE); } } }

这里仅仅是注册了 AnnotationAwareAspectJAutoProxyCreator,怎么用,不要着急,后面会用。(下面先把配置文件方式的注册也给介绍了。)

2.2 基于配置文件方式注册

​ AopNamespaceHandler 该类只有一个方法:init(),通过该类的名字我们可以知道,该类是AOP 命名空间处理器,就是就出注册处理AOP 配置文件节点的各种类型的 解析器。

​ 下面解析器:1,2,4 注册到 org.springframework.beans.factory.xml.NamespaceHandlerSupport#parsers map上;

​ 3 不能算是解析是,他是当前AOP的一个装饰器,将其装饰成符合 配置作用域的bean; 注册到 org.springframework.beans.factory.xml.NamespaceHandlerSupport#decorators map上。

​ 这3个解析器,都是实现了 org.springframework.beans.factory.xml.BeanDefinitionParser#parse方法,解析器注册之后,Bean 在注册相应通知实例的时候,就会调用该方法对节点解析。关于Spring IOC注册如何解析,这不AOP这篇文章的范畴里面。

 

java

复制代码

public class AopNamespaceHandler extends NamespaceHandlerSupport { /** * 该方法将 config,aspectj-autoproxy,scoped-proxy,spring-configured 注册到BeanDefinitionParsers */ @Override public void init() { // In 2.0 XSD as well as in 2.5+ XSDs // 1. 这种 解析的是 <aop:aspect id="hamburgerAspect" ref="hamburgerAspectConfig"> 所有切面,通知xml方式配置的。 // 我们可以进入 ConfigBeanDefinitionParser中 // 该类中有各种 有关aop配置文件的标签名 // 还有各种标签解析方法,如:切面、切入点、增强器、通知解析器 registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser()); // 2. 这种 解析的是 <aop:aspectj-autoproxy proxy-target-class="false" expose-proxy="false"/> ,切面还是@AspecdJ注解方式配置的 // 注册 <aspectj-autoproxy/>标签及其解析器 // 该方法,我们可以看到,将AspectJAutoProxyBeanDefinitionParser解析器注册(put)到 NamespaceHandlerSupport 的 parsers map中 // 进入AspectJAutoProxyBeanDefinitionParser看其主要的parse() 解析方法 registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser()); // 3. // proxy,它代理的工作就是——暴露这个bean令其符合其自身作用域。 // 如当前回话:session作用域 // <bean id="userPreferences" class="com.foo.UserPreferences" scope="session"> // <aop:scoped-proxy/> // </bean> // // <bean id="userManager" class="com.foo.UserManager"> // <property name="userPreferences" ref="userPreferences"/> // </bean> registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator()); // 4. // <context:spring-configured/> 主要是通过Spring管理AnnotationBeanConfigurerAspect切面,具体的工作由该切面完成。 // Only in 2.0 XSD: moved to context namespace in 2.5+ registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser()); } }

(1.)这种 解析的是 <aop:aspect id="hamburgerAspect" ref="hamburgerAspectConfig"> ,所有切面、通知xml方式配置的。真正的xml配置方式的解析类

 
 

java

复制代码

// 1. 这种 解析的是 <aop:aspect id="hamburgerAspect" ref="hamburgerAspectConfig"> 所有切面,通知xml方式配置的。 // 我们可以进入 ConfigBeanDefinitionParser中 // 该类中有各种 有关aop配置文件的标签名 // 还有各种标签解析方法,如:切面、切入点、增强器、通知解析器 registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
  • 进入 org.springframework.aop.config.ConfigBeanDefinitionParser#parse方法

     

    java

    复制代码

    class ConfigBeanDefinitionParser implements BeanDefinitionParser { @Override @Nullable public BeanDefinition parse(Element element, ParserContext parserContext) { CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element)); parserContext.pushContainingComponent(compositeDef); // ★★★★1. 这里往下一直走,我们会发现,我们还会注册 AnnotationAwareAspectJAutoProxyCreator.class★★★ configureAutoProxyCreator(parserContext, element); List<Element> childElts = DomUtils.getChildElements(element); for (Element elt: childElts) { String localName = parserContext.getDelegate().getLocalName(elt); if (POINTCUT.equals(localName)) { // 切入点解析 parsePointcut(elt, parserContext); } else if (ADVISOR.equals(localName)) { // 增强器解析 parseAdvisor(elt, parserContext); } else if (ASPECT.equals(localName)) { // 切面解析 parseAspect(elt, parserContext); } } parserContext.popAndRegisterContainingComponent(); return null; } }
    • 跟一下:configureAutoProxyCreator(parserContext, element);

       

      java

      复制代码

      /** * 配置支持 <aop:config/>标签创建的BeanDefinitions所需的自动代理创建者。如果 proxy-target-class 属性设置为"true",则将强制类代理。 * @see AopNamespaceUtils */ private void configureAutoProxyCreator(ParserContext parserContext, Element element) { AopNamespaceUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext, element); } // -> 往下跟 AopNamespaceUtils#registerAspectJAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) /** * xml方式 <aop:aspect id="hamburgerAspect" ref="hamburgerAspectConfig"> */ public static void registerAspectJAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) { // 往下跟 这个 BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement)); useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); registerComponentIfNecessary(beanDefinition, parserContext); } @Nullable public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary( BeanDefinitionRegistry registry, @Nullable Object source) { // 往下跟 这个 return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source); } // ------->就来到了公共的 注册 AnnotationAwareAspectJAutoProxyCreator.class的方法 org.springframework.aop.config.AopConfigUtils#registerOrEscalateApcAsRequired

(2.)这种 解析的是 <aop:aspectj-autoproxy proxy-target-class="false" expose-proxy="false"/>,切面还是@AspecdJ注解方式配置的。

所以还是下面 AspectJAutoProxyBeanDefinitionParser() 的解析过程,走的还是 注解配置方式的注册流程

 
 

java

复制代码

// 2. 这种 解析的是 <aop:aspectj-autoproxy proxy-target-class="false" expose-proxy="false"/> ,切面还是@AspecdJ注解方式配置的 // 注册 <aspectj-autoproxy/>标签及其解析器 // 该方法,我们可以看到,将AspectJAutoProxyBeanDefinitionParser解析器注册(put)到 NamespaceHandlerSupport 的 parsers map中 // 进入AspectJAutoProxyBeanDefinitionParser看其主要的parse() 解析方法 registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
  • 进入 AspectJAutoProxyBeanDefinitionParser 的 parser()方法:

     

    java

    复制代码

    class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser { /** * 解析 * @param element * @param parserContext */ @Override @Nullable public BeanDefinition parse(Element element, ParserContext parserContext) { // 1. 注册标签解析器,默认使用 AnnotationAwareAspectJAutoProxyCreator AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element); // 2. 解析 <aop:include> 子标签,记录到 BeanDefinition 到 includePatterns 属性中 extendBeanDefinition(element, parserContext); return null; } }
    • 进入 1. 注册标签解析器,默认使用 AnnotationAwareAspectJAutoProxyCreator

       
           

      java

      复制代码

      // 1. 注册标签解析器,默认使用 AnnotationAwareAspectJAutoProxyCreator AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
      • 进入方法:

         

        java

        复制代码

        public abstract class AopNamespaceUtils { public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary( ParserContext parserContext, Element sourceElement) { // 1. 注册默认的 AnnotationAwareAspectJAutoProxyCreator 到 当前的registry中 BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement)); // 2.获取并处理标签的proxy-target-class和expose-proxy属性 useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement); // 3.注册组件,并发布事件通知 registerComponentIfNecessary(beanDefinition, parserContext); } }
        • 进入1. 注册默认的 AnnotationAwareAspectJAutoProxyCreator 到 当前的registry中

          进入到这里,我们就发现,这里注册的方法 和 注解方式 注册的流程是公共的的了 ,最终都会走到 org.springframework.aop.config.AopConfigUtils#registerOrEscalateApcAsRequired() 该方法进行注册。

           
                   

          java

          复制代码

          // 1. 注册默认的 AnnotationAwareAspectJAutoProxyCreator 到 当前的registry中 BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));
        • 2.就没啥了,添加 标签中的 两个属性,还是解释一下吧;解析的是下面的标签里面的两个属性

           
                   

          xml

          复制代码

          <aop:aspectj-autoproxy proxy-target-class="false" expose-proxy="false"/>

2.3 注册总结

这里我们总结一下 注解方式 和 配置文件方式

注解是基于 @AspectJ;有两种方式,一种是 @EnableAspectJAutoProxy 纯注解方式;一种是 切面用注解,在配置文件中配置 <aop:aspectj-autoproxy proxy-target-class="false" expose-proxy="false"/> 启动AOP自动代理。

配置文件方式:就是纯解析xml标签节点方式。

但是最终我们发现,都会走到 org.springframework.aop.config.AopConfigUtils#registerOrEscalateApcAsRequired 方法来注册 AnnotationAwareAspectJAutoProxyCreator.class

三、构建 通知链,创建代理,并注册到beanFactroy中

首先,我们要明白上一步注册意义,目的是 注册 AnnotationAwareAspectJAutoProxyCreator.class;

而,该类在不按功能划分的角度,从垂直角度看类关系看:找到它的顶级父类 AbstractAutoProxyCreator

image-20220427153205611.png

从该类中可以找到Bean初始化之后的后置处理方法:(这里也就是注册之后,这里处理 目标方法(就是我们要增强器的方法))

我们也要知道,后置处理方法, AOP在这里做的事情就是:执行步骤中的 2,3,4步。

 

java

复制代码

@Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException { if (bean != null) { // 如果beanName不为空则直接使用beanName(FactoryBean则使用&{beanName}),否则使用bean的className Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) != bean) { // 尝试对bean进行增强,创建返回增强后的代理对象 return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }

下面我们以 Spring AOP应用 文章的 第四节 注解方式应用 案例 被代理类 Dog类,切面AnimalAspectJ为例;走wrapIfNecessary(bean, beanName, cacheKey)流程。

 

java

复制代码

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // 已经处理过,直接返回 if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } // 不需要进行增强的bean实例,直接跳过 if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } // 对于AOP的基础支撑类,或者指定不需要被代理的类,设置为不进行代理 if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. // 3.1 获取当前bean的 增强器,通知,拦截器列表 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); // 如果返回的不是空,说明被代理了。 // 则 基于获取的Advisor为当前bean创建代理对象 if (specificInterceptors != DO_NOT_PROXY) { // cacheKey 是被增强的类, 该类的拦截器(通知)如果不为空,那么这里就是TRUE this.advisedBeans.put(cacheKey, Boolean.TRUE); // 3.2 创建代理对象 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); // 3.3.1 放进盛放代理对象的 map this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } // 3.3.2 盛放包装的 增强器map this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; }

3.1 获取当前bean的通知列链

大致分为下面4步骤:

  • 1、调用 findCandidateAdvisor方法,找出候选的 通知列表;
  • 2、从候选列表中筛选出 可以应用于当前bean的 通知列表;
  • 3、为了添加一个 ExposeInvocationInterceptor拦截器作为 通知链的头一个;
  • 4、对通知链排序。
 

java

复制代码

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware { // 进入该方法 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); // 是个空方法,由子类实现: // 这里有两个子类:BeanNameAutoProxyCreator、AbstractAdvisorAutoProxyCreator protected abstract Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource customTargetSource) throws BeansException; }

我们进入:AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean()方法

 

java

复制代码

public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator { @Nullable private BeanFactoryAdvisorRetrievalHelper advisorRetrievalHelper; @Override @Nullable protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) { // 进入,看这个核心流程 // 查找该bean对应的所有符合条件的Advisors(增强器) List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { // 这个 null值是 父类AbstractAutoProxyCreator的 return DO_NOT_PROXY; } return advisors.toArray(); } /** * Find all candidate Advisors to use in auto-proxying. 查找所有用于自动代理的候选Advisor(增强器)。 * @return the List of candidate Advisors 返回候选增强器列表 */ protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) { // 1. 调用 findCandidateAdvisor方法,找出候选的 通知列表 List<Advisor> candidateAdvisors = findCandidateAdvisors(); // 2. 从候选列表中筛选出 可以应用于当前bean的 通知列表 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); // 3. 这里就是为了添加一个 ExposeInvocationInterceptor拦截器作为 通知链的头一个。 extendAdvisors(eligibleAdvisors); // 对Advisor进行排序 if (!eligibleAdvisors.isEmpty()) { // 4. 对通知链排序 eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; } // 3. 该类的一个空方法,有子类实现,只有一个子类:AspectJAwareAdvisorAutoProxyCreator 就是我们注册那个类 protected void extendAdvisors(List<Advisor> candidateAdvisors) { } }

3.1.1 调用 findCandidateAdvisor方法,找出候选的 通知列表

​ 这个方法,取的是缓存 cachedAdvisorBeanNames bean对应的 通知链;或者去beanFactory中去找通知链,并缓存到cachedAdvisorBeanNames 中。

​ 这里开始会有一个: beanName 为 :org.springframework.context.event.internalEventListenerProcessor 的,这个 就是 AnnotationAwareAspectJAutoProxyCreator 注册到Spring Bean中的 key值,通过它,利用该方法可以找到对应的切面-通知类列表,注意,这里会缓存,当 beanName是我们 的目标类(被AOP代理的类)的时候,下下步findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);就会从这个候选列表中找到可以匹配的通知列表。

​ 这里是 :注意此时通知的类型:InstantiationModelAwarePointcutAdvisorImpl 

image-20220427172027710.png

 

java

复制代码

//1. 调用 findCandidateAdvisor方法,找出候选的 通知列表 List<Advisor> candidateAdvisors = findCandidateAdvisors();

 

java

复制代码

// 方法位置:org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findCandidateAdvisors /** * Find all candidate Advisors to use in auto-proxying. 查找所有用于自动代理的候选Advisor(增强器)。 * @return the List of candidate Advisors 返回候选增强器列表 */ protected List<Advisor> findCandidateAdvisors() { Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available"); // 进入该方法 return this.advisorRetrievalHelper.findAdvisorBeans(); }

 

java

复制代码

// 方法位置 org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper#findAdvisorBeans public List<Advisor> findAdvisorBeans() { // Determine list of advisor bean names, if not cached already. 确定advisor bean名称列表(如果尚未缓存)。 String[] advisorNames = this.cachedAdvisorBeanNames; if (advisorNames == null) { // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let the auto-proxy creator apply to them! // 不要在这里初始化FactoryBeans:我们需要让所有常规Bean保持未初始化状态,以便让自动代理创建者应用于它们! advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false); this.cachedAdvisorBeanNames = advisorNames; } if (advisorNames.length == 0) { return new ArrayList<>(); } List<Advisor> advisors = new ArrayList<>(); for (String name : advisorNames) { if (isEligibleBean(name)) { if (this.beanFactory.isCurrentlyInCreation(name)) { if (logger.isDebugEnabled()) { logger.debug("Skipping currently created advisor '" + name + "'"); } } else { try { // 这里 就是 通知类加到通知链里面 advisors.add(this.beanFactory.getBean(name, Advisor.class)); } // 省略一万字.... } } } return advisors; }

findCandidateAdvisors();方法走完,回到 3.1的主流程,进入2.

3.1.2 从候选列表中筛选出 可以应用于当前bean的 通知列表
 

java

复制代码

// 2. 从候选列表中筛选出 可以应用于当前bean的 通知列表 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);

 

java

复制代码

// 方法位置:org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply // 2. /** * Search the given candidate Advisors to find all Advisors that * can apply to the specified bean. * 从候选的增强器列表中找到 可以应用于指定的bean的所有增强器 * @param candidateAdvisors the candidate Advisors 候选列表 * @param beanClass the target's bean class 指定bean的class * @param beanName the target's bean name 指定bean的name * @return the List of applicable Advisors 返回可以应用于当前bean的增强器列表 * @see ProxyCreationContext#getCurrentProxiedBeanName() */ protected List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { // 保存 当前代理的bean实例的名称 到当前代理创建的上下文中,(用ThreadLocal保存) ProxyCreationContext.setCurrentProxiedBeanName(beanName); try { // ★★ 进入该方法 // 去找符合的当前bean的增强器 return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); } finally { // 上面保存当前的beanName,在去找到符合的增强器之后,用完,这里将ThreadLocal置为null ProxyCreationContext.setCurrentProxiedBeanName(null); } }

 

java

复制代码

// 进入该方法 org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply /** * 从候选的Advisors列表知道适用于 当前bean的 增强器 * @param candidateAdvisors 候选的Advisors增强器 * @param clazz 目标类 * @return 从候选的Advisors列表知道适用于 当前bean的 增强器 * (may be the incoming List as-is) */ public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) { // 为空直接返回 if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } // 盛放最终的筛选结果 List<Advisor> eligibleAdvisors = new ArrayList<>(); for (Advisor candidate : candidateAdvisors) { // 判断 每一个候选的增强器 是否可以应用于当前的bean(targetClass) // 如果可以就加入 eligibleAdvisors // canApply(candidate, clazz)就是用于 判断 每一个候选的增强器 是否可以应用于当前的bean(targetClass) if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } // 还不知道 canApply(candidate, clazz, hasIntroductions) 这个有啥区别,先不管了。 boolean hasIntroductions = !eligibleAdvisors.isEmpty(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor) { // already processed continue; } if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; }

3.1.3 为了添加一个 ExposeInvocationInterceptor拦截器作为 通知链的头一个
 

java

复制代码

// 3. 这里就是为了添加一个 ExposeInvocationInterceptor拦截器作为 通知链的头一个。 extendAdvisors(eligibleAdvisors);

image-20220427172342514.png

解释一下:为啥让 ExposeInvocationInterceptor拦截器作为 通知链的头一个

​ 在Spring AOP中,ExposeInvocationInterceptor拦截器通常作为通知链的头一个拦截器,其作用是将当前的方法调用信息暴露给其他的切面通知。当一个方法被代理时,Spring AOP会创建一个代理对象,并在代理对象的方法调用前后执行切面通知。

​ 而ExposeInvocationInterceptor拦截器的作用是在方法调用前将当前的方法调用信息绑定到ThreadLocal中,以便其他的切面通知可以获取到该方法调用信息。

​ 通过将ExposeInvocationInterceptor拦截器作为通知链的头一个拦截器,可以确保在其他的切面通知执行时,可以通过AopContext.currentInvocation()方法获取到当前的方法调用信息。这样其他的切面通知就可以获取到方法的参数、方法名、目标对象等相关信息,从而实现更灵活的切面编程。

​ 需要注意的是,为了能够使用ExposeInvocationInterceptor拦截器,目标对象必须实现Spring的AopProxy接口,并且在配置AOP时需要将ExposeInvocationInterceptor拦截器添加到通知链的头部。

3.1.4 对通知链排序
 

java

复制代码

// 4. 对通知链排序 eligibleAdvisors = sortAdvisors(eligibleAdvisors);

image-20220427172509607.png

对比,3.1.3 小结 通知没排序时候的截图;这里我们就可以印证 (Spring AOP应用 文章的案例)说的关于 注解通知排序的问题了。(为啥是倒序,后面再将执行器链执行过程会说。)

3.1 getAdvicesAndAdvisorsForBean()流程走完,回到 wrapIfNecessary(bean, beanName, cacheKey);继续 3.2

3.2 创建代理对象

大致分为下面6步骤:

  • 1、创建代理工厂;
  • 2、设置 proxyTargetClass 值;
  • 3、为了添加一个 ExposeInvocationInterceptor拦截器作为 通知链的头一个;
  • 4、将通知其构建成Advisor类型;
  • 5、创建代理对象;
  • 6、缓存代理。
 

java

复制代码

// 3.2 创建代理对象 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

 

java

复制代码

// 方法位置:org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#createProxy /** * Create an AOP proxy for the given bean. 给 给定的bean创建 AOP代理 * @param beanClass the class of the bean * @param beanName the name of the bean * @param specificInterceptors ★当前bean的 增强器列表 (所以这里参数命名为:特殊的拦截器) * @param targetSource the TargetSource for the proxy, already pre-configured to access the bean * @return the AOP proxy for the bean 返回该bean的AOP代理 * @see #buildAdvisors */ protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) { if (this.beanFactory instanceof ConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } // 创建代理工厂 ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.copyFrom(this); // 3.2.1 // 这个就是看我们在 aop配置文件或者 @EnableAspectJAutoProxy 的参数 proxyTargetClass是否为 true; // 如果为true:就是用CGLIB代理 if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { evaluateProxyInterfaces(beanClass, proxyFactory); } } // 3.2.2 // buildAdvisors 为了将增强器其构建成Advisor类型 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { // 这里表明已经对增强器、通知做前置过滤了,表明增强器列表都是 通知类了 // 这里会将 设置为true proxyFactory.setPreFiltered(true); } // 3.2.3 return proxyFactory.getProxy(getProxyClassLoader()); }

3.2.1 proxyTargetClass 设置
 

java

复制代码

if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { evaluateProxyInterfaces(beanClass, proxyFactory); } }

  • proxyTargetClass
    • true
      • 目标对象实现了接口 – 使用CGLIB代理
      • 目标对象没有接口(只有实现类) – 使用CGLIB代理
    • false
      • 目标对象实现了接口 – 使用JDK动态代理机制(代理所有实现了的接口)
      • 目标对象没有接口(只有实现类) – 使用CGLIB代理机制
3.2.2 将通知其构建成Advisor类型
 

java

复制代码

// buildAdvisors 为了将增强器其构建成Advisor类型 Advisor[] advisors = buildAdvisors(beanName, specificInterceptors); // 通知放入代理工厂中 proxyFactory.addAdvisors(advisors);

先说明一下,为什么要将增强器构建成Advisor类型;

在 (3.1.1)小结中, 我们我们说过,specificInterceptors 获取的候选的通知l列表中通知的类型是 InstantiationModelAwarePointcutAdvisorImpl

该类是个实现类:沿着该类往上找,可以发现该类就是 Advisor的子类,这个类,我们特殊介绍一下吧;下面的代码块,我们可以看到,该类的构造方法,初始化了通知(或者增强器)的各种属性,如:通知的方法,参数,优先级,工厂等等;再 着重介绍一个参数 instantiatedAdvice:是初始化通知的实际类型。 

image-20220427194023817.png

 

java

复制代码

class InstantiationModelAwarePointcutAdvisorImpl implements InstantiationModelAwarePointcutAdvisor, AspectJPrecedenceInformation, Serializable { public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut, Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) { this.declaredPointcut = declaredPointcut; // 通知对应的 切入点表达式类AspectJExpressionPointcut this.declaringClass = aspectJAdviceMethod.getDeclaringClass(); // 获取该通知所在的 切面类class this.methodName = aspectJAdviceMethod.getName(); // 通知方法 的方法名 this.parameterTypes = aspectJAdviceMethod.getParameterTypes(); // 通知方法 的方法参数 this.aspectJAdviceMethod = aspectJAdviceMethod; // 通知方法 this.aspectJAdvisorFactory = aspectJAdvisorFactory; // 通知方法对应的切面工厂 this.aspectInstanceFactory = aspectInstanceFactory; // 通知方法对应的切面实例化工厂 this.declarationOrder = declarationOrder; // 该通知方法的 优先级 this.aspectName = aspectName; // 通知方法所在的 切面类 if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) { // 懒加载方式 // Static part of the pointcut is a lazy type. Pointcut preInstantiationPointcut = Pointcuts.union( aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut); // Make it dynamic: must mutate from pre-instantiation to post-instantiation state. // If it's not a dynamic pointcut, it may be optimized out // by the Spring AOP infrastructure after the first evaluation. this.pointcut = new PerTargetInstantiationModelPointcut( this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory); this.lazy = true; } else { //单例方式的切面 // A singleton aspect. this.pointcut = this.declaredPointcut; this.lazy = false; // instantiateAdvice(this.declaredPointcut)方法 // 将通知构建成对应类型: // AspectJAroundAdvice 环绕 ,AspectJMethodBeforeAdvice 前置通知,AspectJAfterAdvice 后置通知 // AspectJAfterReturningAdvice 后置返回通知, AspectJAfterThrowingAdvice 异常通知 this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut); } } }

3.2.3 创建代理对象
 

java

复制代码

// 3.2.3 return proxyFactory.getProxy(getProxyClassLoader());

 

java

复制代码

// 方法位置: org.springframework.aop.framework.ProxyFactory#getProxy(java.lang.ClassLoader) public Object getProxy(@Nullable ClassLoader classLoader) { // 先看createAopProxy(),再看getProxy(classLoader) return createAopProxy().getProxy(classLoader); } // 方法位置:org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy protected final synchronized AopProxy createAopProxy() { // 如果是第一次,代理标志这只为true;有监听器添加监听器 if (!this.active) { activate(); } // 创建代理 return getAopProxyFactory().createAopProxy(this); } //下面看 createAopProxy(this)

可以通过断点方式查看代理:(这里是CGLIB代理) 

image-20220427195243973.png

 

java

复制代码

// 进入 createAopProxy() // 这里就进入到代理的选择了 // 代码位置: org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { // 指定了 optimize:true 或者 proxyTargetClass:true 或者 没有实现接口 if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); // 目标类找不到 抛异常 if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } // 目标类是接口 或者 class是由代理类动态通过getProxyClass方法或newProxyInstance方法生成的 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } // 否则使用CGLIB代理 return new ObjenesisCglibAopProxy(config); } // 否则使用JDK动态代理 else { return new JdkDynamicAopProxy(config); } } }

由于我们在 Spring AOP应用 文章的案例 注解方式里面的 proxyTargetClass=true,所以这里走的是 ObjenesisCglibAopProxy(config) ;(不要担心,后面JDK代理也会讲的,因为AOP后面在执行代理方法(就是在执行通知链的代码实公共的。))

好! createAopProxy()返回的类型我们知道,我们就可以进入到 ObjenesisCglibAopProxy类中 .getProxy(classLoader)方法了。

 

java

复制代码

class CglibAopProxy implements AopProxy, Serializable { @Override public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource()); } try { Class<?> rootClass = this.advised.getTargetClass(); Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy"); Class<?> proxySuperClass = rootClass; if (ClassUtils.isCglibProxyClass(rootClass)) { proxySuperClass = rootClass.getSuperclass(); Class<?>[] additionalInterfaces = rootClass.getInterfaces(); for (Class<?> additionalInterface : additionalInterfaces) { this.advised.addInterface(additionalInterface); } } // Validate the class, writing log messages as necessary. validateClassIfNecessary(proxySuperClass, classLoader); // Configure CGLIB Enhancer... // 看,这里就是配置 CGLIB代理了。 Enhancer enhancer = createEnhancer(); if (classLoader != null) { enhancer.setClassLoader(classLoader); if (classLoader instanceof SmartClassLoader && ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) { enhancer.setUseCache(false); } } enhancer.setSuperclass(proxySuperClass); enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised)); enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE); enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader)); Callback[] callbacks = getCallbacks(rootClass); Class<?>[] types = new Class<?>[callbacks.length]; for (int x = 0; x < types.length; x++) { types[x] = callbacks[x].getClass(); } // fixedInterceptorMap only populated at this point, after getCallbacks call above enhancer.setCallbackFilter(new ProxyCallbackFilter( this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset)); enhancer.setCallbackTypes(types); // Generate the proxy class and create a proxy instance. return createProxyClassAndInstance(enhancer, callbacks); } catch (CodeGenerationException | IllegalArgumentException ex) { throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() + ": Common causes of this problem include using a final class or a non-visible class", ex); } catch (Throwable ex) { // TargetSource.getTarget() failed throw new AopConfigException("Unexpected AOP exception", ex); } } }

如果是 JDK代理的.getProxy(classLoader)方法 ,我们也看看吧:

 

java

复制代码

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { @Override public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isDebugEnabled()) { logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource()); } Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true); findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); // 看,这里利用JDK方式创建代理 return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); } }

OK,代理对象完成,回到 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary方法,执行最后的 3.3.1。

3.2.4 缓存代理
 

java

复制代码

// 3.3.1 放进盛放代理对象的 map this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy;

至此 wrapIfNecessary方法走完,也就是完成了对 目标对象的增强(AOP方式增强代理对象);即完成对 当前的beanName被AOP代理的bean,完成后置处理。

下面就是我们利用代理对象执行目标方法。

四、执行目标方法时,转为执行代理

4.1 确定代理方式

下面两个截图,一个是:CGLIB方式,一个是JDK方式。

image-20220425155254376.png

image-20220425154945033.png

4.1.1 CGLIB方式

CGLIB方式利用的是 CglibAopProxy里面的内部类 DynamicAdvisedInterceptor 的 intercept()方法执行的。

 

java

复制代码

class CglibAopProxy implements AopProxy, Serializable { /** * General purpose AOP callback. Used when the target is dynamic or when the proxy is not frozen. * 通用AOP回调。当目标是动态的或代理未冻结时使用 * * 这里基于 CGLIB代理 通过是实现 MethodInterceptor#intercept方法 */ private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable { private final AdvisedSupport advised; public DynamicAdvisedInterceptor(AdvisedSupport advised) { this.advised = advised; } /** * 这里执行代理方法,就是当我们执行我们的目标方法(被增强的方法)的时候,其实就是来到这里,执行的代理方法; * 从拦截器链中执行 代理类,目标方法,目标方法参数,代理方法 */ @Override @Nullable public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; Object target = null; TargetSource targetSource = this.advised.getTargetSource(); try { if (this.advised.exposeProxy) { // Make invocation available if necessary. oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true; } // Get as late as possible to minimize the time we "own" the target, in case it comes from a pool... target = targetSource.getTarget(); Class<?> targetClass = (target != null ? target.getClass() : null); // 1、 // 这里是获取当前通知的 增强器(或者叫拦截器)链,其实就是 被代理方法method的 通知,拦截器之类的这些. List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; // Check whether we only have one InvokerInterceptor: that is, // no real advice, but just reflective invocation of the target. // 检查我们是否只有一个InvokerInterceptor:也就是说,没有真正的通知,只有对目标的反射调用。 // 拦截器链为空,按直接当做一个普通的代理执行就行了。 if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { // 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 = methodProxy.invoke(target, argsToUse); } // 这里执行器链不为空,那就需要 通过 else { // We need to create a method invocation... 创建方法的调用 // 2、 // proceed()就进入到 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()方法, // 利用责任链模式 处理 拦截器链执行代理方法 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); } // 处理返回值。 retVal = processReturnType(proxy, target, method, retVal); return retVal; } finally { if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); } // 通过 判断代理接口 暴露出去; // 如果 属性 exposeProxy设置成了true,那就需要恢复AOP的代理上下文为执行代理之前的状态 if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } } }

4.1.2 JDK方式
 

java

复制代码

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable { /** * Implementation of {@code InvocationHandler.invoke}. * <p>Callers will see exactly the exception thrown by the target, * unless a hook method throws an exception. */ @Override @Nullable public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; TargetSource targetSource = this.advised.targetSource; Object target = null; try { // 省略一万字............. // Get the interception chain for this method. // 1、获取通知链 List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); // Check whether we have any advice. If we don't, we can fallback on direct // reflective invocation of the target, and avoid creating a MethodInvocation. if (chain.isEmpty()) { Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { // 2、创建 ReflectiveMethodInvocation,并调用proceed()方法执行通知链 // We need to create a method invocation... MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); // Proceed to the joinpoint through the interceptor chain. retVal = invocation.proceed(); } // Massage return value if necessary. // 对返回值处理 Class<?> returnType = method.getReturnType(); if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { // Special case: it returned "this" and the return type of the method // is type-compatible. Note that we can't help if the target sets // a reference to itself in another returned object. retVal = proxy; } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { throw new AopInvocationException( "Null return value from advice does not match primitive return type for: " + method); } return retVal; } finally { if (target != null && !targetSource.isStatic()) { // Must have come from TargetSource. targetSource.releaseTarget(target); } if (setProxyContext) { // Restore old proxy. AopContext.setCurrentProxy(oldProxy); } } } }

两种代理方式执行的过程大致相似;

主要就分了两步:

  • 1、获取通知链;
  • 2、执行通知链。

4.2 获取通知链

 

java

复制代码

// 这里是获取当前通知的 增强器(或者叫拦截器)链,其实就是 被代理方法method的 通知,拦截器之类的这些. List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

 

java

复制代码

// 来到下面代码位置:org.springframework.aop.framework.AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) { MethodCacheKey cacheKey = new MethodCacheKey(method); // 如果缓存中已经有目标类的通知链了,就直接返回了;没有了就是去获取,然后再放到缓存中 List<Object> cached = this.methodCache.get(cacheKey); if (cached == null) { // 进入该方法 cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass); this.methodCache.put(cacheKey, cached); } return cached; }

 

java

复制代码

// 代码位置:org.springframework.aop.framework.DefaultAdvisorChainFactory#getInterceptorsAndDynamicInterceptionAdvice public class DefaultAdvisorChainFactory implements AdvisorChainFactory, Serializable { /** * 构建拦截器链,并返回 * 可以是各种类型的拦截器;如:普通的通知类型的增强器;引介增强器等 */ @Override public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, @Nullable Class<?> targetClass) { // This is somewhat tricky... We have to process introductions first, // but we need to preserve order in the ultimate list. List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length); //创建拦截器链长度 Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass()); // 目标类 boolean hasIntroductions = hasMatchingIntroductions(config, actualClass); // 判断 通知列表中是否包含匹配的引介。 AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); // 这里是通知的适配器 // config.getAdvisors()我们就可以获取匹配目标方法的到通知列表,可以看下面图的Debug for (Advisor advisor : config.getAdvisors()) { if (advisor instanceof PointcutAdvisor) { // 这里是我们正常的 通知类型 // Add it conditionally. PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor; if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) { MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); // 方法匹配器 //上面的mm类型是 TrueMethodMatcher类型,这里应该无论如何都是true if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) { MethodInterceptor[] interceptors = registry.getInterceptors(advisor); if (mm.isRuntime()) { // Creating a new object instance in the getInterceptors() method // isn't a problem as we normally cache created chains. // 在getInterceptors()方法中创建新的对象实例不是问题,因为我们通常会缓存创建的链。 for (MethodInterceptor interceptor : interceptors) { // 注意这里将通知构建成 InterceptorAndDynamicMethodMatcher,再添加到执行器链的。 // 为什么呢? 我们可以去 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()看看 // 在执行的时候,有一个是判断是该动态类型拦截器的if interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); } } else { // 我们的切面-通知方法 mm.isRuntime() = false,所以会走这里添加到通知链中。 interceptorList.addAll(Arrays.asList(interceptors)); } } } } // 增强器类型如果是 引介增强器 // 进入下面的流程时,我们假设是我们 a-spring-test-pro工程中, // aopintroduction 包中demo: 自定义 引介增强器 CustomIntroductionInterceptor else if (advisor instanceof IntroductionAdvisor) { // 那么,这里会是 默认的DefaultIntroductionAdvisor IntroductionAdvisor ia = (IntroductionAdvisor) advisor; // 那么,ia.getClassFilter()是获取该引介增强器的类过滤器 // 那么,ia.getClassFilter().matches(actualClass) 恒为 true if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) { // 那么, registry.getInterceptors(advisor)获取的就是 CustomIntroductionInterceptor // 我们知道了 CustomIntroductionInterceptor Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } else { // 其他类型的拦截器 Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; } }

config.getAdvisors()我们就可以获取匹配目标方法的到通知列表:

image-20220428101911674.png

OK,通知链获取完,下面就是精彩的执行部分了。回到主方法intercept()或 invoke()

不论是CGLIB:

 

java

复制代码

// proceed()就进入到 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()方法, // 利用责任链模式 处理 拦截器链执行代理方法 retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

不论是 JDK:

 

java

复制代码

MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain); retVal = invocation.proceed();

一个 new CglibMethodInvocation 和 new ReflectiveMethodInvocation ,

但是都是调用的 org.springframework.aop.framework.ReflectiveMethodInvocation#proceed()方法

4.3 执行通知链

 

java

复制代码

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable { protected final List<?> interceptorsAndDynamicMethodMatchers; private int currentInterceptorIndex = -1; /** * 这里是利用 一个List链表存放 要被执行的拦截器,通过 数组下标的移动 和递归实现的 责任链模式。 * 可以看本人在学习 Mybatis源码时,Mybatis源码中对于 责任链模式的使用和本人找的demo案例: * https://gitee.com/old_yogurt/mybatis-sources-learning * mybatis-3-mybatis-3.5.2 工程中 plugin包中 ① InterceptorChain就是利用List+for循环实现责任链 ② base包是 demo案例 */ @Override @Nullable public Object proceed() throws Throwable { // We start with an index of -1 and increment early. // 从索引 -1开始,然后递增 // 当 拦截器链执行到最后一个时,调用 invokeJoinpoint方法 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { // 1、 // 利用反射执行方法 return invokeJoinpoint(); } // 先执行++ 操作,再获取拦截器 Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); // 可以看一下 InterceptorAndDynamicMethodMatcher里面的注释,封装了 拦截器 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 { // 动态匹配失败。 // 跳过此拦截器并调用链中的下一个拦截器。 // 递归 return proceed(); } } else { // It's an interceptor, so we just invoke it: The pointcut will have // been evaluated statically before this object was constructed. // 它是一个拦截器(仅仅是一个拦截器,不是 InterceptorAndDynamicMethodMatcher 类型的), // 所以我们只需调用它本身的invoke方法执行即可:在构造这个对象之前,切入点将被静态地计算。 // 2、 // AspectJMethodBeforeAdvice return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); } } /** * 使用反射调用连接点。子类可以覆盖此项以使用自定义调用。 * 可以进入子类:CglibAopProxy 的内部类 CglibMethodInvocation中对该方法的实现 * * @return 连接点的返回值 * @throws Throwable if invoking the joinpoint resulted in an exception */ @Nullable protected Object invokeJoinpoint() throws Throwable { // 利用反射执行方法 return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments); } }

先看一下 interceptorsAndDynamicMethodMatchers属性,就是通知列表。

image-20220428103241958.png

。。。这里有点难解释。

这里先不说通知链为啥是倒序的,流程走完再解释。

(1、)处位置,只有当递归进入到最底层,也就是索引下标为0时,执行的是我们目标方法的代码;

(2、)处位置是执行通知链的地方。

4.3.1 入栈
入栈,来到栈深度 1 :

currentInterceptorIndex = 0

image-20220428104326190.png

 

java

复制代码

// 方法位置: public class ExposeInvocationInterceptor implements MethodInterceptor, PriorityOrdered, Serializable { private static final ThreadLocal<MethodInvocation> invocation = new NamedThreadLocal<>("Current AOP method invocation"); @Override public Object invoke(MethodInvocation mi) throws Throwable { MethodInvocation oldInvocation = invocation.get(); invocation.set(mi); try { return mi.proceed(); //这里是又回到 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() 拦截器链中 } finally { invocation.set(oldInvocation); } } }

该方法目标,暴露当前目标方法:放到invocation的当前线程中。

image-20220428104634112.png

好,调用 mi.proceed();回到 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() 拦截器链中。

入栈,来到栈深度 2 :

此时 currentInterceptorIndex = 1,对应 AspectJAfterThrowingAdvice,栈深度2。

image-20220428104943758.png

 

java

复制代码

// 代码位置 public class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice, Serializable { @Override public Object invoke(MethodInvocation mi) throws Throwable { try { // 执行方法 // 调用拦截器链 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() return mi.proceed(); } catch (Throwable ex) { // 注意这里是在 catch块中 if (shouldInvokeOnThrowing(ex)) { // 调用 org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod() 通知基础类的方法 // 执行 异常通知方法 invokeAdviceMethod(getJoinPointMatch(), null, ex); } throw ex; } } }

因为是 异常通知,所以异常通知发放在catch块中了;目前不论有没有异常,我们都先是执行 mi.proceed();,回到 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()中,保留 catch块中的 invokeAdviceMethod(getJoinPointMatch(), null, ex);

入栈,来到栈深度 3 :

此时 currentInterceptorIndex = 2,对应 AspectJAfterThrowingAdvice,栈深度3。

image-20220428105602062.png

 

java

复制代码

public class AfterReturningAdviceInterceptor implements MethodInterceptor, AfterAdvice, Serializable { private final AfterReturningAdvice advice; @Override public Object invoke(MethodInvocation mi) throws Throwable { Object retVal = mi.proceed(); // 因为这里是 AfterReturning,所以,先执行 目标方法,或者环绕通知pj.proceed()下面部分的代码; this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis()); //再执行 AfterReturning return retVal; } }

这里我们看到 后置返回通知,也是先回到 mi.proceed(); 保留 this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());

入栈,来到栈深度 4 :

此时 currentInterceptorIndex = 3,对应 AspectJAfterAdvice,栈深度4。 

image-20220428105948390.png

 

java

复制代码

public class AspectJAfterAdvice extends AbstractAspectJAdvice implements MethodInterceptor, AfterAdvice, Serializable { @Override public Object invoke(MethodInvocation mi) throws Throwable { try { // 执行方法 // 调用拦截器链 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() return mi.proceed(); } finally { // 注意这里是 finally块中 // 调用 org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod() 通知基础类的方法 // 执行通知方法 invokeAdviceMethod(getJoinPointMatch(), null, null); } } }

这里我们看到 返回通知,也是先回到 mi.proceed(); 保留 finally块中的 invokeAdviceMethod(getJoinPointMatch(), null, null);

入栈,来到栈深度 5 :

此时 currentInterceptorIndex = 4,对应 AspectJAroundAdvice,栈深度5。

image-20220428110221090.png

 

java

复制代码

// 代码位置 public class AspectJAroundAdvice extends AbstractAspectJAdvice implements MethodInterceptor, Serializable { @Override public Object invoke(MethodInvocation mi) throws Throwable { if (!(mi instanceof ProxyMethodInvocation)) { throw new IllegalStateException("MethodInvocation is not a Spring ProxyMethodInvocation: " + mi); } ProxyMethodInvocation pmi = (ProxyMethodInvocation) mi; // 这里会 new MethodInvocationProceedingJoinPoint,该类里面的proceed()处理执行环绕通知 ProceedingJoinPoint pjp = lazyGetProceedingJoinPoint(pmi); // 获取1. 方法的连接点 JoinPointMatch jpm = getJoinPointMatch(pmi); // 调用 org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod() 通知基础类的方法 // 2. // 执行通知方法 return invokeAdviceMethod(pjp, jpm, null, null); } }

在切面中,环绕通知的方法,通常都会像下面这样写,这时候,上面通过(1.)获取当前方法的连接点,(2.)执行连点的调用,就会来到这里的环绕通知方法:

先执行System.out.println("Around before ...");

然后调用 pj.proceed();

又回到 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(),

保留 System.out.println("Around after ...");

所以,我们就看到了,控制台打印的 Around before ...

这就是为什么环绕通知的前置处理先执行,@Before在后面了。

 

java

复制代码

/** * 该通知会将目标方法封装起来, * 并且 Around before ... -> 在 @Before前; * Around after ... -> 在 @After前. * @param pj */ @Around("pointCut()") public void xxx(ProceedingJoinPoint pj) { try { System.out.println("Around before ..."); pj.proceed(); System.out.println("Around after ..."); } catch (Throwable throwable) { throwable.printStackTrace(); } }

image-20220428110658671.png

OK,回到 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed()

入栈,来到栈深度 6 :

此时 currentInterceptorIndex = 5,对应 MethodBeforeAdviceInterceptor,栈深度6。

image-20220428111703279.png

 

java

复制代码

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable { private final MethodBeforeAdvice advice; @Override public Object invoke(MethodInvocation mi) throws Throwable { // 1. 执行 前置通知,然后再接着下面的 proceed()往下走 this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis()); // 2. return mi.proceed(); } }

1、就要执行 @Before前置通知了。 

image-20220428112045074.png

2、回到mi.proceed();

入栈,来到栈深度 7 :

此时 currentInterceptorIndex = 6, 栈深度7。

if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1)成立;利用反射执行目标方法。

image-20220428112251623.png

 

java

复制代码

// 该 if条件成立, if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) { // 执行目标方法 return invokeJoinpoint(); }

image-20220428112552947.png

至此,链中所有方法已经入栈,现在开始出栈。

4.3.2 出栈
来到栈深度 7 ,出栈:

(前置通知 @Before执行完成出栈)

回到 @Before前置通知的 MethodBeforeAdviceInterceptor#invoke方法:看下图也可以看出来;

image-20220428112851372.png

也就是要 回到 return mi.proceed();

来到栈深度 6 ,出栈:

(当前处于@Around环绕通知中,要执行环绕通知的后半段)

往外出 :就是回到 org.springframework.aop.framework.ReflectiveMethodInvocation#proceed的这个位置: 

image-20220428135115715.png

return执行完成;来到这里;执行环绕通知的后半段:

image-20220428120340014.png

 

java

复制代码

// 代码位置 public class MethodInvocationProceedingJoinPoint implements ProceedingJoinPoint, JoinPoint.StaticPart { @Override public Object proceed() throws Throwable { // 调用的拦截器链,执行方法 org.springframework.aop.framework.ReflectiveMethodInvocation.proceed() // 执行(通知? 增强器? 引介? 拦截器?)都对。 环绕通知走这个。 return this.methodInvocation.invocableClone().proceed(); } } // 执行 this.methodInvocation.invocableClone().proceed(); // 来到环绕通知后面 @Around("pointCut()") public void xxx(ProceedingJoinPoint pj) { try { System.out.println("Around before ..."); pj.proceed(); System.out.println("Around after ..."); } catch (Throwable throwable) { throwable.printStackTrace(); } }

如下图所示,环绕通知后半段执行:

image-20220428120509393.png

来到栈深度 5 ,出栈:

(此时处于 @After 后置通知)

image-20220428120845606.png

后置通知 org.springframework.aop.aspectj.AspectJAfterAdvice#invoke,就来到了 前面入栈时候 保留的finally块部分:

image-20220428140100408.png

来到栈深度 4 ,出栈:

(后置返回通知 @AfterReturning

image-20220428140230424.png

执行后置返回通知方法:

image-20220428140413456.png

来到栈深度 3 ,出栈:

(这里来到 @AfterReturning org.springframework.aop.aspectj.AspectJAfterThrowingAdvice#invoke

image-20220428140536346.png

如果有异常,就会执行下面 catch块的内容,如果没有就继续出栈了 

image-20220428140717378.png

来到栈深度 2 ,出栈:

org.springframework.aop.interceptor.ExposeInvocationInterceptor#invoke

image-20220428140834379.png

这里会恢复现场:

image-20220428140956146.png

来到栈深度 1 ,出栈:

image-20220428141415735.png

就回到了代理方法的位置,以CGLIB为例: org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept;对后续处理。

image-20220428141541044.png

再回到我们的 main方法:

image-20220428141740117.png

OK,整个通知链执行完成。。。 (完结撒花)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值