共计 3661 个字符,预计需要花费 10 分钟才能阅读完成。
前言
在 Spring AOP – 注解方式使用介绍(长文详解)中,作者介绍了 Spring AOP 注解方式的使用方式。算是给咱们的 Spring AOP 源码分析开了个头,做了一点知识点的铺垫。
在开始学习 Spring AOP 的源码之前,如果你还没有学习过 Spring IoC 的源码,最好先去学习下 Spring IoC。
- Spring IoC – Spring IoC 的设计
- Spring IoC – IoC 容器初始化 源码解析
- Spring IoC – 依赖注入 源码解析
Spring AOP 只作用于 Spring Bean 的特性说明了 Spring AOP 和 Spring IOC 的关系,AOP 依赖于 IOC 容器来管理,后面的源码分析也会涉及到 Spring IoC 的源码内容。
下面,假设你已经学习过 Spring IoC 的相关内容和 Spring AOP 的相关使用,让我们开始吧。
本文耗费了作者大量心力,希望能对你有所帮助。
我们前面一直说的 Spring AOP 源码解析,源码这么多,我们真正关注的内容是什么?
Spring AOP 的功能是什么?从使用上直白的说,就是根据我们的配置来生成代理类,拦截指定的方法,将指定的 advice 织入。
我们应该关注的内容总结下来就是:
- Spring AOP 的触发时机是什么时候?
- Spring AOP 是如何解析我们配置的 Aspect,生成 Advisors 链的?
- Spring AOP 是如何生成代理类的,如何将 advice 织入代理类?
另外,整个源码解析的内容过多,为了读者的阅读体验和自己的时间安排。我将按照上面的总结的三点,分三篇向您解读。
本文的源码解析是以 AOP 注释方式使用来作为例子讲解的,和其他方式主要是在于触发入口不同,核心的流程还是差不多的。希望读者们能够触类旁通。
一、开启 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.
Useful when operating at the bean definition level (as opposed to @Bean method/instance level) is desired or necessary.
就是说,它需要和 @Configuration
配合使用 ,在@Configuration
之前已注册的 Bean,可以由 ImportBeanDefinitionRegistrar
接口来处理,这个接口提供了如下一个方法:
void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)
这个方法可以拿到 @Import
的这个 class 的 Annotation Metadata
,以及此时的BeanDefinitionRegistry
对象,通过BeanDefinitionRegistry
就可以拿到目前所有注册的 BeanDefinition,可以自定义逻辑来动态注册一些你觉得必要的 BeanDefinition。
PS: 很多开源框架与 Spring 集成的时候都扩展了这个接口,比如 Apollo 的 ApolloConfigRegistrar、mybatis 的 MapperScannerRegistrar 等等
扩展阅读 https://www.logicbig.com/tuto…
在 AspectJAutoProxyRegistrar
中,实际上就是将 AspectJAnnotationAutoProxyCreator
的BeanDefinition
注册到 IoC 容器当中。
下面是 AopConfigUtils
中执行注册的逻辑代码片段。
先来一条分割线,理解完上面的流程之后,我们继续来思考。
为什么把 AspectJAnnotationAutoProxyCreator
注入到 Spring IoC 容器中,自动代理就开启了呢?
让我们来寻找这个触发点。
二、自动代理的触发时机
首先,我们来看一下 AspectJAnnotationAutoProxyCreator
的继承结构。
有没有发现,AspectJAnnotationAutoProxyCreator
居然是一个BeanPostProcessor
!
学习过 Spring IoC 之后的你,应该对这个类极其的敏感。
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
的内容。我们下次再会。
如果本文有帮助到你,希望能点个赞,这是对我的最大动力。