在 Spring AOP - 注解方式使用介绍(长文详解) 中,作者介绍了Spring AOP 注解方式的使用方式。算是给咱们的Spring AOP 源码分析开了个头,做了一点知识点的铺垫。
在开始学习Spring AOP的源码之前,如果你还没有学习过Spring IoC的源码,最好先去学习下Spring IoC。
Spring AOP 只作用于Spring Bean 的特性说明了Spring AOP和Spring IOC 的关系,AOP 依赖于 IOC 容器来管理,后面的源码分析也会涉及到Spring IoC 的源码内容。
下面,假设你已经学习过Spring IoC 的相关内容和Spring AOP的相关使用,让我们开始吧。
我们前面一直说的Spring AOP源码解析,源码这么多,我们真正关注的内容是什么?
Spring AOP的功能是什么?从使用上直白的说,就是根据我们的配置来生成代理类,拦截指定的方法,将指定的advice织入。
我们应该关注的内容总结下来就是:
另外,整个源码解析的内容过多,为了读者的阅读体验和自己的时间安排。我将按照上面的总结的三点,分三篇向您解读。
本文的源码解析是以AOP注释方式使用来作为例子讲解的,和其他方式主要是在于触发入口不同,核心的流程还是差不多的。希望读者们能够触类旁通。
我们在 Spring AOP - 注解方式使用介绍(长文详解) 中介绍了 @EnableAspectJAutoProxy 注解,是用来开启 Spring AOP注解的使用。这个的作用就是自动让 ioc 容器中的所有 advisor 来匹配方法,advisor 内部都是有 advice 的,让它们内部的 advice 来执行拦截处理(注:advisor 可以就看成 pointcut + advise的一个组合对象)。引用这个注解的英文翻译就是开启自动代理。
那么里面的玄机是什么呢?
我们进去先进到这个注解里面看看,
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
boolean proxyTargetClass() default false;
boolean exposeProxy() default false;
}
@Import(AspectJAutoProxyRegistrar.class) 使用 @Import 注解将 AspectJAutoProxyRegistrar 注入到 IoC 容器当中。
对这个注解不熟悉的可以去了解一下 @Import Annotation in Spring Framework
我们看一看这个 AspectJAutoProxyRegistrar ,
注意,这个类实现了 ImportBeanDefinitionRegistrar 接口。
这个接口是一个 Spring 很强大的扩展接口 ,它的作用是:
Register additional bean definitions when processing @Configuration classes.
就是说, 它需要和 @Configuration 配合使用 ,在 @Configuration 之前已注册的Bean,可以由 ImportBeanDefinitionRegistrar 接口来处理,这个接口提供了如下一个方法:
void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)
这个方法可以拿到 @Import 的这个class的 Annotation Metadata ,以及此时的 BeanDefinitionRegistry 对象,通过 BeanDefinitionRegistry 就可以拿到目前所有注册的BeanDefinition,可以自定义逻辑来动态注册一些你觉得必要的BeanDefinition。
扩展阅读 https://www.logicbig.com/tuto...
在 AspectJAutoProxyRegistrar 中,实际上就是将 AspectJAnnotationAutoProxyCreator 的 BeanDefinition 注册到IoC 容器当中。
下面是 AopConfigUtils 中执行注册的逻辑代码片段。
先来一条分割线,理解完上面的流程之后,我们继续来思考。
为什么把 AspectJAnnotationAutoProxyCreator 注入到Spring IoC 容器中,自动代理就开启了呢?
让我们来寻找这个触发点。
首先,我们来看一下 AspectJAnnotationAutoProxyCreator 的继承结构。
有没有发现, AspectJAnnotationAutoProxyCreator 居然是一个 BeanPostProcessor !
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
我们先回顾思考下代理模式的实现思路: (接口) + 真实实现类 + 代理类 。
是不是要先有了真实的实现类,才能够生成代理类?!
在 Spring IoC - 依赖注入 源码解析 中我们介绍了Spring Bean 创建的过程,在执行完 Step1 创建实例对象 createBeanInstance() 和 Step2 属性装配 populateBean() 之后,我们才算 得到一个真正的实现类 。
在Step3 initializeBean() 中,IoC容器会处理Bean初始化之后的各种回调事件,然后返回一个“可能经过加工”的bean对象。
其中就包括了 BeanPostProcessor 的 postProcessBeforeInitialization 回调 和 postProcessAfterInitialization 回调。
而 AspectJAnnotationAutoProxyCreator 恰恰是一个 BeanPostProcessor (原谅我又重复了一次),那就很容易联想到,Spring AOP 就是在这一步, 进行代理增强 !
那么接下来,我们就来看看这里面的玄机。
可以看到实际回调的 postProcessBeforeInitialization 和 postProcessAfterInitialization 这两个方式是在 AbstractAdvisorAutoProxyCreator 中 override 的。
源码位置: AbstractAdvisorAutoProxyCreator
JavaDoc 很清楚的注明了 postProcessAfterInitialization 会执行创建代理类的操作,用配置的interceptors 来创建一个代理类,并且告诉我们去看 getAdvicesAndAdvisorsForBean ,看来这会是一个关键方法,这里我们先不急,继续往下看 wrapIfNecessary 方法。
源码位置: AbstractAutoProxyCreator#wrapIfNecessary(..)
这个方法里面有核心的就是两个点,我在上图中分别用 **** TODO-1 **** 和 **** TODO-2 **** 标识出来了。
TODO-1 就是 获取当前的Spring Bean 适配的 advisors 。
TODO-2 就是 创建代理类 。
我们接下去的章节就是详细讲解这两个 TODO 的内容。我们下次再会。
如果本文有帮助到你,希望能点个赞,这是对我的最大动力。