万字长文!深入解析SpringAOP源码,从无到有分分钟搞定

一、认识AOP及其使用 二、AOP的特点 2.1 Spring AOP
2.1.1 他是基于动态代理实现的

Spring 提供了很多的实现AOP的方式:Spring 接口方式,schema配置方式和注解的方式. 如果使用接口方式引入AOP, 就是用JDK提供的动态代理来实现. 如果没有使用接口的方式引入. 那么就是使用CGLIB来实现的

研究使用接口方式实现AOP, 目的是为了更好地理解spring使用动态代理实现AOP的两种方
2.1.2 Spring提供了对AspectJ的支持, 但只提供了部分功能的支持: 即AspectJ的切点解析(表达式)和匹配
我们在写切面的时候,经常使用到的@Aspect, @Before, @Pointcut, @After, @AfterReturning, @AfterThrowing等就是AspectJ提供的.
我们知道AspectJ很好用, 效率也很高. 那么为什么Spring不使用AspectJ全套的东西呢? 尤其是AspectJ的静态织入.
先来看看AspectJ有哪些特点
AspectJ的特点 1. AspectJ属于静态织入. 他是通过修改代码实现的. 它的织入时机有三种 1) Compile-time weaving: 编译期织入. 例如: 类A使用AspectJ增加了一个属性. 类B引用了类A, 这个场景就需要在编译期的时候进行织入, 否则类B就没有办法编译, 会报错. 2) Post-compile weaving: 编译后织入.也就是已经生成了.class文件了, 或者是都已经达成jar包了. 这个时候, 如果我们需要增强, 就要使用到编译后织入 3) Loading-time weaving: 指的是在加载类的时候进行织入. 2. AspectJ实现了对AOP变成完全的解决方案. 他提供了很多Spring AOP所不能实现的功能 3. 由于AspectJ是在实际代码运行前就完成了织入, 因此可以认为他生成的类是没有额外运行开销的.

扩展: 这里为什么没有使用到AspectJ的静态织入呢? 因为如果引入静态织入, 需要使用AspectJ自己的解析器. AspectJ文件是以aj后缀结尾的文件, 这个文件Spring是没有办法, 因此要使用AspectJ自己的解析器进行解析. 这样就增加了Spring的成本.
三、 AOP的配置方式 上面说了Spring AOP和AspectJ. 也说道了AspectJ定义了很多注解, 比如: @Aspect, @Pointcut, @Before, @After等等. 但是, 我们使用Spring AOP是使用纯java代码写的. 也就是说他完全属于Spring, 和AspectJ没有什么关系. Spring只是沿用了AspectJ中的概念. 包括AspectJ提供的jar包的注解. 但是, 并不依赖于AspectJ的功能.
Spring AOP有三种配置方式.
  • 第一种: 基于接口方式的配置. 在Spring1.2版本, 提供的是完全基于接口方式实现的* 第二种: 基于schema-based配置. 在spring2.0以后使用了xml的方式来配置.* 第三种: 基于注解@Aspect的方式. 这种方式是最简单, 方便的. 这里虽然叫做AspectJ, 但实际上和AspectJ一点关系也没有.
因为我们在平时工作中主要使用的是注解的方式配置AOP, 而注解的方式主要是基于第一种接口的方式实现的. 所以, 我们会重点研究第一种和第三种配置方式.
3.1 基于接口方式的配置. 在Spring1.2版本, 提供的是完全基于接口方式实现的
这种方式是最古老的方式, 但由于spring做了很好的向后兼容, 所以, 现在还是会有很多代码使用这种方式, 比如:声明式事务.
那么, 在没有引入AspectJ的时候, Spring是如何实现AOP的呢? 我们来看一个例子:
1.定义一个业务逻辑接口类
package com.lxl.www.aop.interfaceAop; /** * 使用接口方式实现AOP, 默认通过JDK的动态代理来实现. 非接口方式, 使用的是cglib实现动态代理 * * 业务接口类-- 计算器接口类 * * 定义三个业务逻辑方法 */ public interface IBaseCalculate {int add(int numA, int numB); int sub(int numA, int numB); int div(int numA, int numB); int multi(int numA, int numB); int mod(int numA, int numB); }

2.定义业务逻辑类
package com.lxl.www.aop.interfaceAop; //业务类,也是目标对象import com.lxl.www.aop.Calculate; import org.springframework.aop.framework.AopContext; import org.springframework.stereotype.Service; /** * 业务实现类 -- 基础计算器 */public class BaseCalculate implements IBaseCalculate {@Override public int add(int numA, int numB) { System.out.println("执行目标方法: add"); return numA + numB; }@Override public int sub(int numA, int numB) { System.out.println("执行目标方法: sub"); return numA - numB; }@Override public int multi(int numA, int numB) { System.out.println("执行目标方法: multi"); return numA * numB; }@Override public int div(int numA, int numB) { System.out.println("执行目标方法: div"); return numA / numB; }@Override public int mod(int numA, int numB) { System.out.println("执行目标方法: mod"); int retVal = ((Calculate) AopContext.currentProxy()).add(numA, numB); return retVal % numA; } }

3. 定义通知类
前置通知
package com.lxl.www.aop.interfaceAop; import org.springframework.aop.MethodBeforeAdvice; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * 定义前置通知 * 实现MethodBeforeAdvice接口 */ public class BaseBeforeAdvice implements MethodBeforeAdvice {/** * * @param method 切入的方法 * @param args 切入方法的参数 * @param target 目标对象 * @throws Throwable */ @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("===========进入beforeAdvice()============"); System.out.println("前置通知--即将进入切入点方法"); System.out.println("===========进入beforeAdvice() 结束============\n"); }}

后置通知
package com.lxl.www.aop.interfaceAop; import org.aspectj.lang.annotation.AfterReturning; import org.springframework.aop.AfterAdvice; import org.springframework.aop.AfterReturningAdvice; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * 后置通知 * 实现AfterReturningAdvice接口 */ public class BaseAfterReturnAdvice implements AfterReturningAdvice {/** * * @param returnValue 切入点执行完方法的返回值,但不能修改 * @param method 切入点方法 * @param args 切入点方法的参数数组 * @param target 目标对象 * @throws Throwable */ @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("\n==========进入afterReturning()==========="); System.out.println("后置通知--切入点方法执行完成"); System.out.println("==========进入afterReturning() 结束=========== "); }}

环绕通知
package com.lxl.www.aop.interfaceAop; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * 环绕通知 * 实现MethodInterceptor接口 */ public class BaseAroundAdvice implements MethodInterceptor {/** * invocation :连接点 */ @Override public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println("===========around环绕通知方法 开始==========="); // 调用目标方法之前执行的动作 System.out.println("环绕通知--调用方法之前: 执行"); // 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行 Object returnValue = https://www.it610.com/article/invocation.proceed(); System.out.println("环绕通知--调用方法之后: 执行"); System.out.println("===========around环绕通知方法结束==========="); return returnValue; }}

配置类
package com.lxl.www.aop.interfaceAop; import org.springframework.aop.framework.ProxyFactoryBean; import org.springframework.context.annotation.Bean; /** * 配置类 */ public class MainConfig {/** * 被代理的对象 * @return */ @Bean public IBaseCalculate baseCalculate() { return new BaseCalculate(); }/** * 前置通知 * @return */ @Bean public BaseBeforeAdvice baseBeforeAdvice() { return new BaseBeforeAdvice(); }/** * 后置通知 * @return */ @Bean public BaseAfterReturnAdvice baseAfterReturnAdvice() { return new BaseAfterReturnAdvice(); }/** * 环绕通知 * @return */ @Bean public BaseAroundAdvice baseAroundAdvice() { return new BaseAroundAdvice(); }/** * 使用接口方式, 一次只能给一个类增强, 如果想给多个类增强, 需要定义多个ProxyFactoryBean * 而且, 曾增强类的粒度是到类级别的. 不能指定对某一个方法增强 * @return */ @Bean public ProxyFactoryBean calculateProxy() { ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean(); proxyFactoryBean.setInterceptorNames("baseAfterReturnAdvice", "baseBeforeAdvice", "baseAroundAdvice"); proxyFactoryBean.setTarget(baseCalculate()); return proxyFactoryBean; }}

之前说过, AOP是依赖ioc的, 必须将其注册为bean才能实现AOP功能
方法入口
package com.lxl.www.aop.interfaceAop; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class InterfaceMainClass{public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class); IBaseCalculate calculate = context.getBean("calculateProxy", IBaseCalculate.class); System.out.println(calculate.getClass()); calculate.add(1, 3); }}

执行结果:
===========进入beforeAdvice()============ 前置通知--即将进入切入点方法 ===========进入beforeAdvice() 结束=======================around环绕通知方法 开始=========== 环绕通知--调用方法之前: 执行 执行目标方法: add 环绕通知--调用方法之后: 执行 ===========around环绕通知方法结束=====================进入afterReturning()=========== 后置通知--切入点方法执行完成 ==========进入afterReturning() 结束===========

通过观察, 我们发现, 执行的顺序是: 前置通知-->环绕通知的前置方法 --> 目标逻辑 --> 环绕通知的后置方法 --> 后置通知.
那么到底是先执行前置通知, 还是先执行环绕通知的前置方法呢? 这取决于配置文件的配置顺序
这里,我们将环绕通知放在最后面, 所以, 环绕通知在前置通知之后执行.
@Bean public ProxyFactoryBean calculateProxy() { ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean(); proxyFactoryBean.setInterceptorNames( "baseAfterReturnAdvice", "baseBeforeAdvice", "baseAroundAdvice"); proxyFactoryBean.setTarget(baseCalculate()); return proxyFactoryBean; }

那么, 如果我们将环绕通知放在前置通知之前. 就会先执行环绕通知
@Bean public ProxyFactoryBean calculateProxy() { ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean(); proxyFactoryBean.setInterceptorNames("baseAroundAdvice", "baseAfterReturnAdvice", "baseBeforeAdvice"); proxyFactoryBean.setTarget(baseCalculate()); return proxyFactoryBean; }

运行结果
===========around环绕通知方法 开始=========== 环绕通知--调用方法之前: 执行 ===========进入beforeAdvice()============ 前置通知--即将进入切入点方法 ===========进入beforeAdvice() 结束============执行目标方法: add==========进入afterReturning()=========== 后置通知--切入点方法执行完成 ==========进入afterReturning() 结束=========== 环绕通知--调用方法之后: 执行 ===========around环绕通知方法结束===========

上面提到了责任链, 那么什么是责任链呢? 如下图所示: 万字长文!深入解析SpringAOP源码,从无到有分分钟搞定
文章图片
Spring AOP源码分析 有一条流水线. 比如生产流水线. 里面有许多道工序. 完成工序1 ,才能进行工序2, 依此类推.
结合上面的demo, 来看一个责任链调用的demo.
上面我们定义了两个方法. 一个是前置通知BaseBeforeAdvice 实现了MethodBeforeAdvice, 另一个是环绕通知BaseAroundAdvice 实现了MethodInterceptor. 如果想把这两个通知放在一个链上. 那么他们必须实现相同的接口. 但是, 现在不同.
我们知道环绕通知, 有两部分, 一部分是环绕通知的前置通知, 一部分是环绕通知的后置通知. 所以, 我们可以将前置通知看作是环绕通知的前置通知部分.
package com.lxl.www.aop.interfaceAop.chainDemo; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.aop.MethodBeforeAdvice; /** * 为什么 我们可以让MethodBeforeAdvice 前置通知继承自环绕通知的接口呢? * 主要原因是, 环绕通知的前半部分, 就是前置通知 */ public class BeforeAdviceInterceptor implements MethodInterceptor {// 前置通知 MethodBeforeAdvice methodBeforeAdvice; public BeforeAdviceInterceptor(MethodBeforeAdvice methodBeforeAdvice) { this.methodBeforeAdvice = methodBeforeAdvice; }/** * 使用了环绕通知的前半部分. 就是一个前置通知 * @param invocation the method invocation joinpoint * @return * @throws Throwable */ @Override public Object invoke(MethodInvocation invocation) throws Throwable { methodBeforeAdvice.before(invocation.getMethod(), invocation.getArguments(), invocation.getClass()); return invocation.proceed(); } }

这段代码包装了前置通知, 让其扩展为实现MethodInterceptor接口. 这是一个扩展接口的方法.
接下来我们要创建一条链. 这条链就可以理解为流水线上各个工人. 每个工人处理一个工序. 为了能够统一调用. 所有的工人都要实现同一个接口. 责任链的定义如下:
/** * 把一条链上的都初始化 * * 有一条链, 这条链上都有一个父类接口 MethodInterceptor. * 也就是说, 链上都已一种类型的工人. 但每种工人的具体实现是不同的. 不同的工人做不同的工作 * * 这里定义了一个责任链. 连上有两个工人. 一个是前置通知. 一个是环绕通知. * 前置通知和环绕通知实现的接口是不同的. 为了让他们能够在一条链上工作. 我们自定义了一个MethodBeforeAdviceInterceptor * 相当于为BaseBeforeAdvice()包装了一层MethodInterceptor */List list = new ArrayList<>(); list.add(new BeforeAdviceInterceptor(new BaseBeforeAdvice())); list.add(new BaseAroundAdvice());

这里定义了一个责任链. 连上有两个工人. 一个是前置通知. 一个是环绕通知.
前置通知和环绕通知实现的接口是不同的. 为了让他们能够在一条链上工作. 我们自定义了一个MethodBeforeAdviceInterceptor相当于为BaseBeforAdvice()包装了一层MethodInterceptor接下来是责任链的调用.
/** * 责任链调用 */ public static class MyMethodInvocation implements MethodInvocation {// 这是责任链 protected List list; // 目标类 protected final BaseCalculate target; public MyMethodInvocation(List list) { this.list = list; this.target = new BaseCalculate(); }int i = 0; public Object proceed() throws Throwable { if (i == list.size()) { /** * 执行到责任链的最后一环, 执行目标方法 */ return target.add(2, 2); } MethodInterceptor interceptor = list.get(i); i++; /** * 执行责任链调用 * 这个调用链第一环是: 包装后的前置通知 * 调用链的第二环是: 环绕通知. * 都执行完以后, 执行目标方法. */ return interceptor.invoke(this); }@Override public Object getThis() { return target; }@Override public AccessibleObject getStaticPart() { return null; }@Override public Method getMethod() { try { return target.getClass().getMethod("add", int.class, int.class); } catch (NoSuchMethodException e) { e.printStackTrace(); } return null; }@Override public Object[] getArguments() { return new Object[0]; } }}

这里重点看 proceed () 方法. 我们循环获取了list责任链的通知, 然后执行invoke()方法
万字长文!深入解析SpringAOP源码,从无到有分分钟搞定
文章图片
Spring AOP源码分析 proceed() 方法是一个链式循环. 刚开始i=0, list(0)是前置通知, 当调用到前置通知的时候, BeforeAdviceInterceptor.invoke()方法, 又调用了invocation.proceed()方法, 回到了MyMethodInvocation.proceed()方法.
然后i=1, list(1)是环绕通知, 当调用环绕通知的时候, 又调用了invocation.proceed(); 有回到了MyMethodInvocation.proceed()方法.
这是已经是list的最后一环了, 后面不会在调用invoke()方法了. 二是执行目标方法. 执行结束以后, 整个调用结束.
这就是一个调用链.
对于责任链有两点: 1. 要有一个统一的调用, 也就是一个共同的抽象类.
2. 使用循环或者递归, 完成责任链的调用
总结:
上面这种方式, 使用的是ProxyFactoryBean 代理bean工厂的方式. 他有两个限制:
public class ProxyFactoryBean extends ProxyCreatorSupport implements FactoryBean, BeanClassLoaderAware, BeanFactoryAware { ...... @Override @Nullable public Object getObject() throws BeansException { /** * 初始化通知链: 将通知放入链中 * 后面初始化的时候, 是通过责任链的方式调用这些通知链的的. * 那么什么是责任链呢? */ initializeAdvisorChain(); if (isSingleton()) { /** * 创建动态代理 */ return getSingletonInstance(); } else { if (this.targetName == null) { logger.info("Using non-singleton proxies with singleton targets is often undesirable. " + "Enable prototype proxies by setting the 'targetName' property."); } return newPrototypeInstance(); } } ...... }
1. 一次只能给1个类增强, 如果给多个类增强就需要定义多个ProxyFactoryBean
2. 增强的粒度只能到类级别上, 不能指定给某个方法增强.这样还是有一定的限制
3.2 基于注解@Aspect的方式. 这种方式是最简单, 方便的. 这里虽然叫做AspectJ, 但实际上和AspectJ一点关系也没有.
3.2.1 @Aspect切面的解析原理
上面第一种方式详细研究了接口方式AOP的实现原理. 注解方式的AOP, 最后就是将@Aspect 切面类中的@Befor, @After等注解解析成Advisor. 带有@Before类会被解析成一个Advisor, 带有@After方法的类也会被解析成一个Advisor.....其他通知的方法也会被解析成Advisor 在Advisor中定义了增强的逻辑, 也就是@Befor和@After等的逻辑, 以及需要增强的方法, 比如div方法.
下面来分析一下使用注解@Aspect , @Before, @After的实现原理. 上面已经说了, 就是将@Before, @After生成Advisor
这里一共有三个部分.
  • 第一部分: 解析@Aspect下带有@Before等的通知方法, 将其解析为Advisor* 第二部分: 在createBean的时候, 创建动态代理* 第三部分: 调用. 调用的时候, 执行责任链, 循环里面所有的通知. 最后输出结果.
下面我们按照这三个部分来分析.
第一步: 解析@Aspect下带有@Before等的通知方法, 将其解析为Advisor. 如下图:
万字长文!深入解析SpringAOP源码,从无到有分分钟搞定
文章图片
Spring AOP源码分析 第一步是在什么时候执行的呢?
在createBean的时候, 会调用很多PostProcessor后置处理器, 在调用第一个后置处理器的时候执行.执行的流程大致是: 拿到所有的BeanDefinition,判断类上是不是带有@Aspect注解. 然后去带有@Aspect注解的方法中找@Before, @After, @AfterReturning, @AfterThrowing, 每一个通知都会生成一个Advisor
第二步: 在createBean的时候, 创建动态代理
万字长文!深入解析SpringAOP源码,从无到有分分钟搞定
文章图片
Spring AOP源码分析 createBean一共有三个阶段, 具体在哪一个阶段创建的动态代理呢?
整体流程是:
在createBean的时候, 在初始化完成以后调用bean的后置处理器. 拿到所有的Advisor, 循环遍历Advisor, 然后根据execution中的表达式进行matchs匹配. 和当前创建的这个bean进行匹配, 匹配上了, 就创建动态代理.
pointcut的种类有很多. 上面代码提到过的有:
package com.lxl.www.aop.interfaceAop.chainDemo; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.aop.MethodBeforeAdvice; /** * 为什么 我们可以让MethodBeforeAdvice 前置通知继承自环绕通知的接口呢? * 主要原因是, 环绕通知的前半部分, 就是前置通知 */ public class BeforeAdviceInterceptor implements MethodInterceptor {// 前置通知 MethodBeforeAdvice methodBeforeAdvice; public BeforeAdviceInterceptor(MethodBeforeAdvice methodBeforeAdvice) { this.methodBeforeAdvice = methodBeforeAdvice; }/** * 使用了环绕通知的前半部分. 就是一个前置通知 * @param invocation the method invocation joinpoint * @return * @throws Throwable */ @Override public Object invoke(MethodInvocation invocation) throws Throwable { methodBeforeAdvice.before(invocation.getMethod(), invocation.getArguments(), invocation.getClass()); return invocation.proceed(); } }

而我们注解里面是按照execution表达式的方式进行匹配的
第三步: 调用. 调用的时候, 执行责任链, 循环里面所有的通知. 最后输出结果.
万字长文!深入解析SpringAOP源码,从无到有分分钟搞定
文章图片
Spring AOP源码分析 3.2.2 AOP切面源码分析
源码分析也分为三部分
  • 1. 解析切面
  • 2. 创建动态代理
  • 3. 调用
/** * 把一条链上的都初始化 * * 有一条链, 这条链上都有一个父类接口 MethodInterceptor. * 也就是说, 链上都已一种类型的工人. 但每种工人的具体实现是不同的. 不同的工人做不同的工作 * * 这里定义了一个责任链. 连上有两个工人. 一个是前置通知. 一个是环绕通知. * 前置通知和环绕通知实现的接口是不同的. 为了让他们能够在一条链上工作. 我们自定义了一个MethodBeforeAdviceInterceptor * 相当于为BaseBeforeAdvice()包装了一层MethodInterceptor */List list = new ArrayList<>(); list.add(new BeforeAdviceInterceptor(new BaseBeforeAdvice())); list.add(new BaseAroundAdvice());

源码分析的入口, AOP注解:
package com.lxl.www.aop; import org.springframework.beans.factory.annotation.Configurable; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configurable // 使用注解的方式引入AOP @EnableAspectJAutoProxy @ComponentScan("com.lxl.www.aop") public class MainConfig {}

引入AOP, 我们需要在配置文件中增加@EnableAspectJAutoProxy代理. 那么想要去掉AOP的引入, 只需要将这个注解注释掉就可以了. 这个注解解释整个AOP的入口.
接下来, 进入到注解类
/** * 责任链调用 */ public static class MyMethodInvocation implements MethodInvocation {// 这是责任链 protected List list; // 目标类 protected final BaseCalculate target; public MyMethodInvocation(List list) { this.list = list; this.target = new BaseCalculate(); }int i = 0; public Object proceed() throws Throwable { if (i == list.size()) { /** * 执行到责任链的最后一环, 执行目标方法 */ return target.add(2, 2); } MethodInterceptor interceptor = list.get(i); i++; /** * 执行责任链调用 * 这个调用链第一环是: 包装后的前置通知 * 调用链的第二环是: 环绕通知. * 都执行完以后, 执行目标方法. */ return interceptor.invoke(this); }@Override public Object getThis() { return target; }@Override public AccessibleObject getStaticPart() { return null; }@Override public Method getMethod() { try { return target.getClass().getMethod("add", int.class, int.class); } catch (NoSuchMethodException e) { e.printStackTrace(); } return null; }@Override public Object[] getArguments() { return new Object[0]; } }}

这是, 我们看到EnableAspectJAutoProxy类增加了一个@Import注解类, 我们知道Import注解可以向IoC容器中增加一个bean.
下面进入到 AspectJAutoProxyRegistrar类
package org.springframework.context.annotation; import org.springframework.aop.config.AopConfigUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.type.AnnotationMetadata; class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {/** * Register, escalate, and configure the AspectJ auto proxy creator based on the value * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing * {@code @Configuration} class. */ @Override public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); if (enableAspectJAutoProxy != null) { if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } }}

我们看到, 使用ImportBeanDefinitionRegistrar注册了一个BeanDefinition.
需要记住的是, 通常使用ImportBeanDefinitionRegistrar结合@Import可以向容器中注册一个BeanDefinition.
如何注册的呢? 看具体实现.
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

注册名字是internalAutoProxyCreator的AnnotationAwareAspectJAutoProxyCreator
@Nullable public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary( BeanDefinitionRegistry registry, @Nullable Object source) {/** * 注册一个AnnotationAwareAspectJAutoProxyCreator类型的bean定义 */ return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); }

如上结构梳理如下:
万字长文!深入解析SpringAOP源码,从无到有分分钟搞定
文章图片
Spring AOP源码分析 我们看到, 注册了类AnnotationAwareAspectJAutoProxyCreator类型的bean. 这是一个什么样的类呢? 我们来看一下类的结构. 这个类的继承结构很庞大, 我们只看和本次内容相关的继承结构
万字长文!深入解析SpringAOP源码,从无到有分分钟搞定
文章图片
Spring AOP源码分析 解析切面, 创建动态代理, 都是在bean的后置处理器中进行的, 下面对照着AOP的实现原理以及createBean(创建bean)的过程来看
万字长文!深入解析SpringAOP源码,从无到有分分钟搞定
文章图片
Spring AOP源码分析 上图是bean加载过程中调用的9次后置处理器. 在创建bean之前调用了InstantiationAwareBeanPostProcessor后置处理器判断是否需要为这个类创建AOP, 也就是解析切面的过程. 所以在AnnotationAwareAspectJAutoProxyCreator里面实现了InstantiationAwareBeanPostProcessor后置处理器的接口. 重写了postProcessBeforeInstantiation方法.
在createBean的第三阶段初始化之后, 要创建AOP的动态代理, 调用了BeanPostProcess后置处理器, AnnotationAwareAspectJAutoProxyCreator也实现了BeanPostProcess接口. 重写了postProcessAfterInitialization.
同时也需要处理AOP的循环依赖的问题, 处理循环依赖是在属性赋值之前调用SmartInstantiationAwareBeanPostProcessor后置处理器, 然后重写getEarlyBeanReference方法. 我们看到AnnotationAwareAspectJAutoProxyCreator也实现了SmartInstantiationAwareBeanPostProcessor接口. 并重写getEarlyBeanReference方法.
【万字长文!深入解析SpringAOP源码,从无到有分分钟搞定】由于篇幅限制的原因,就只能分享一部分内容,需要完整版的小伙伴可以帮忙转发+关注,感谢大家!

    推荐阅读