在 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
的内容。我们下次再会。
如果本文有帮助到你,希望能点个赞,这是对我的最大动力。