死磕Spring之AOP篇 - Spring AOP注解驱动与XML配置

该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读。

Spring 版本:5.1.14.RELEASE

在开始阅读 Spring AOP 源码之前,需要对 Spring IoC 有一定的了解,可查看我的 《死磕Spring之IoC篇 - 文章导读》 这一系列文章

了解 AOP 相关术语,可先查看 《Spring AOP 常见面试题) 》 这篇文章

该系列其他文章请查看:《死磕 Spring 之 AOP 篇 - 文章导读》

通过前面关于 Spring AOP 的所有文章,我们对 Spring AOP 的整个 AOP 实现逻辑进行了比较详细的分析,例如 Spring AOP 的自动代理,JDK 动态代理或 CGLIB 动态代理两种方式创建的代理对象的拦截处理过程等内容都有讲到。本文将会分析 Spring AOP 的注解驱动,如何引入 AOP 模块,包括如何处理 Spring AOP 的 XML 配置。

在 Spring AOP 中可以通过 @EnableAspectJAutoProxy 注解驱动整个 AOP 模块,我们先一起来看看这个注解。

@EnableAspectJAutoProxy 注解

org.springframework.context.annotation.EnableAspectJAutoProxy,开启 Spring AOP 整个模块的注解

/** * @since 3.1 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy { /** * 是否开启类代理,也就是是否开启 CGLIB 动态代理 */ boolean proxyTargetClass() default false; /** * 是否需要暴露代理对象 * @since 4.3.1 */ boolean exposeProxy() default false; }

该注解上面有一个 @Import 注解,它的 value 是 AspectJAutoProxyRegistrar.class 类。

这里先讲一下 @Import 注解的原理,在 Spring IoC 初始化完 BeanFactory 后会有一个 BeanDefinitionRegistryPostProcessor 对其进行后置处理,对配置类(例如 @Configuration 注解标注的 Bean)进行处理,如果这个 BeanDefinition 包含 @Import 注解,则获取注解的值,进行下面的处理:

如果是一个 ImportSelector 对象,则调用其 String[] selectImports(AnnotationMetadata) 方法获取需要导入的 Bean 的名称

否则,如果是一个 ImportBeanDefinitionRegistrar 对象,先保存起来,在后面调用其 registerBeanDefinitions(AnnotationMetadata, BeanDefinitionRegistry) 方法,支持注册相关 Bean

否则,会注册这个 Bean

关于 @Import 注解不熟悉的小伙伴查看我的另一篇 《死磕Spring之IoC篇 - @Bean 等注解的实现原理》 文章

所以说 @EnableAspectJAutoProxy 注解需要标注在能够被 Spring 扫描的类上面,例如 @Configuration 标注的类。其中 AspectJAutoProxyRegistrar 就是 ImportBeanDefinitionRegistrar 的实现类,我们一起来看看。

AspectJAutoProxyRegistrar

org.springframework.context.annotation.AspectJAutoProxyRegistrar,在 @EnableAspectJAutoProxy 注解中被导入

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // <1> 注册一个 AnnotationAwareAspectJAutoProxyCreator 自动代理对象(如果没有注册的话),设置为优先级最高 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); // <2> 获取 @EnableAspectJAutoProxy 注解的配置信息 AnnotationAttributes enableAspectJAutoProxy = AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class); // <3> 如果注解配置信息不为空,则根据配置设置 AnnotationAwareAspectJAutoProxyCreator 的属性 if (enableAspectJAutoProxy != null) { if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) { // 设置 `proxyTargetClass` 为 `true`(开启类代理,也就是开启 CGLIB 动态代理) AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { // 设置 `exposeProxy` 为 `true`(需要暴露代理对象,也就是在 Advice 或者被拦截的方法中可以通过 AopContext 获取代理对象) AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } } } }

可以看到它注册 BeanDefinition 的过程如下:

通过 AopConfigUtils 注册一个 AnnotationAwareAspectJAutoProxyCreator 自动代理对象(如果没有注册的话),设置为优先级最高

获取 @EnableAspectJAutoProxy 注解的配置信息

如果注解配置信息不为空,则根据配置设置 AnnotationAwareAspectJAutoProxyCreator 的属性

如果 proxyTargetClass 为 true,则进行设置(开启类代理,也就是开启 CGLIB 动态代理)

如果 exposeProxy 为 true,则进行设置(需要暴露代理对象,也就是在 Advice 或者被拦截的方法中可以通过 AopContext 获取代理对象)

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zygssw.html