【Spring注解驱动开发】二狗子让我给他讲讲@EnableAspectJAutoProxy注解

简介: 最近,二狗子入职了新公司,新入职的那几天确实有点飘。不过慢慢的,他发现他身边的人各个身怀绝技啊,有Spring源码的贡献者,有Dubbo源码的贡献者,有MyBatis源码的贡献者,还有研究AI的大佬,个个都是大神级别的人物。二狗子有点慌,想起自己虽然入职了,但是比起其他人确实差点远啊。怎么办呢?先从基础补起呗,他发现自己对于Spring的理解还不算太深。于是乎,他让我给他讲讲Spring的@EnableAspectJAutoProxy注解。

注解说明


在配置类上添加@EnableAspectJAutoProxy注解,能够开启注解版的AOP功能。也就是说,AOP中如果要使注解版的AOP功能起作用,就需要在配置类上添加@EnableAspectJAutoProxy注解。 我们先来看下@EnableAspectJAutoProxy注解的源码,如下所示。

package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
 boolean proxyTargetClass() default false;
 boolean exposeProxy() default false;
}

从源码可以看出,@EnableAspectJAutoProxy使用@Import注解引入了AspectJAutoProxyRegister.class对象 。那么,AspectJAutoProxyRegistrar又是什么呢?我们继续点击到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 {
 @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);
   }
  }
 }
}

可以看到AspectJAutoProxyRegistrar类实现了ImportBeanDefinitionRegistrar接口。看下ImportBeanDefinitionRegistrar接口的定义,如下所示。

package org.springframework.context.annotation;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.type.AnnotationMetadata;
public interface ImportBeanDefinitionRegistrar {
 default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
   BeanNameGenerator importBeanNameGenerator) {
  registerBeanDefinitions(importingClassMetadata, registry);
 }
 default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
 }

看到ImportBeanDefinitionRegistrar接口,小伙伴们是不是觉得很熟悉呢。没错,我们在【Spring注解驱动开发】专题前面的文章中介绍过。可以通过ImportBeanDefinitionRegistrar接口实现将自定义的组件添加到IOC容器中。

也就说,@EnableAspectJAutoProxy注解使用AspectJAutoProxyRegistrar对象自定义组件,并将相应的组件添加到IOC容器中。

调试Sprin


g源码我们在AspectJAutoProxyRegistrar类的registerBeanDefinitions()方法中设置断点,如下所示。

微信图片_20211119153312.jpg


接下来,我们以debug的方法来运行AopTest类的testAop01()方法。运行后程序进入到断点位置,如下所示。

微信图片_20211119153319.jpg

可以看到,程序已经暂停在断点位置,而且在IDEA的左下角显示了方法的调用栈。

在AspectJAutoProxyRegistrar类的registerBeanDefinitions()方法,首先调用AopConfigUtils类的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法来注册registry。单看registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法也不难理解,字面含义就是:如果需要的话注册一个AspectJAnnotationAutoProxyCreator。

接下来,我们进入到AopConfigUtils类的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法中,如下所示。

微信图片_20211119153329.jpg

在AopConfigUtils类的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法中,直接调用了重载的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法,我们继续跟代码,如下所示。

微信图片_20211119153337.jpg

微信图片_20211119153356.jpg

可以看到在重载的registerAspectJAnnotationAutoProxyCreatorIfNecessary()方法中直接调用了registerOrEscalateApcAsRequired()方法。在registerOrEscalateApcAsRequired()方法中,传入了AnnotationAwareAspectJAutoProxyCreator.class对象。

我们继续跟进代码,如下所示。

微信图片_20211119153356.jpg


我们可以看到,在registerOrEscalateApcAsRequired()方法中,接收到的Class对象的类型为:org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator。

在registerOrEscalateApcAsRequired()方法中方法中,首先判断registry是否包含org.springframework.aop.config.internalAutoProxyCreator类型的bean。如下所示。

微信图片_20211119153427.jpg

如果registry中包含org.springframework.aop.config.internalAutoProxyCreator类型的bean,则进行相应的处理,从Spring的源码来看,就是将org.springframework.aop.config.internalAutoProxyCreator类型的bean从registry中取出,并且判断cls对象的name值和apcDefinition的beanClassName值是否相等,如果不相等。则获取apcDefinition和cls的优先级,如果apcDefinition的优先级小于cls的优先级,则将apcDefinition的beanClassName设置为cls的name值。相对来说,理解起来还是比较简单的。

我们这里是第一次运行程序,不会进入到 if 条件中,我们继续看代码,如下所示。

微信图片_20211119153434.jpg

这里,使用RootBeanDefinition来创建一个beanDefinition,并且将org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator的Class对象作为参数传递进来。

微信图片_20211119153438.jpg

我们继续往下看代码,最终AopConfigUtils类的registerOrEscalateApcAsRequired()方法中,会通过registry调用registerBeanDefinition()方法注册组件,如下所示。

微信图片_20211119153454.jpg

并且注册的bean的名称为org.springframework.aop.config.internalAutoProxyCreator。

接下来,我们继续看AspectJAutoProxyRegistrar类的registerBeanDefinitions()源码,如下所示。

微信图片_20211119153501.jpg

通过AnnotationConfigUtils类的attributesFor方法来获取@EnableAspectJAutoProxy注解的信息。接下来,就是判断proxyTargetClass属性的值是否为true,如果为true则调用AopConfigUtils类的forceAutoProxyCreatorToUseClassProxying()方法;继续判断exposeProxy属性的值是否为true,如果为true则调用AopConfigUtils类的forceAutoProxyCreatorToExposeProxy()方法。

综上,向Spring的配置类上添加@EnableAspectJAutoProxy注解后,会向IOC容器中注册AnnotationAwareAspectJAutoProxyCreator。

接下来,我们来看下AnnotationAwareAspectJAutoProxyCreator类的结构图。

微信图片_20211119153511.jpg

我们简单梳理下AnnotationAwareAspectJAutoProxyCreato类的核心继承关系,如下所示。

AnnotationAwareAspectJAutoProxyCreator
       --AspectJAwareAdvisorAutoProxyCreator
         --AbstractAdvisorAutoProxyCreator
           --AbstractAutoProxyCreator
             -- ProxyProcessorSupport, SmartInstantiationAwareBeanPostProcessor

查看继承关系可以发现,此类实现了Aware与BeanPostProcessor接口,这两个接口都和Spring bean的初始化有关,由此推测此类主要处理方法都来自这两个接口的实现方法。同时该类也实现了order方法。

好了,二狗子说:有关AnnotationAwareAspectJAutoProxyCreator类的详细代码和执行流程我们后面再讲,他有点消化不了了。

相关文章
|
12天前
|
Java 数据安全/隐私保护 Spring
Java 中 Spring Boot 框架下的 Email 开发
Java 中 Spring Boot 框架下的 Email 开发
263 2
|
13天前
|
运维 Java 程序员
Spring5深入浅出篇:基于注解实现的AOP
# Spring5 AOP 深入理解:注解实现 本文介绍了基于注解的AOP编程步骤,包括原始对象、额外功能、切点和组装切面。步骤1-3旨在构建切面,与传统AOP相似。示例代码展示了如何使用`@Around`定义切面和执行逻辑。配置中,通过`@Aspect`和`@Around`注解定义切点,并在Spring配置中启用AOP自动代理。 进一步讨论了切点复用,避免重复代码以提高代码维护性。通过`@Pointcut`定义通用切点表达式,然后在多个通知中引用。此外,解释了AOP底层实现的两种动态代理方式:JDK动态代理和Cglib字节码增强,默认使用JDK,可通过配置切换到Cglib
|
3天前
|
Java Spring 容器
Spring注解开发,bean的作用范围及生命周期、Spring注解开发依赖注入
Spring注解开发,bean的作用范围及生命周期、Spring注解开发依赖注入
12 1
Spring注解开发,bean的作用范围及生命周期、Spring注解开发依赖注入
|
4天前
|
缓存 NoSQL Java
Spring Cache之本地缓存注解@Cacheable,@CachePut,@CacheEvict使用
SpringCache不支持灵活的缓存时间和集群,适合数据量小的单机服务或对一致性要求不高的场景。`@EnableCaching`启用缓存。`@Cacheable`用于缓存方法返回值,`value`指定缓存名称,`key`定义缓存键,可按SpEL编写,`unless`决定是否不缓存空值。当在类上使用时,类内所有方法都支持缓存。`@CachePut`每次执行方法后都会更新缓存,而`@CacheEvict`用于清除缓存,支持按键清除或全部清除。Spring Cache结合Redis可支持集群环境。
32 5
|
5天前
|
Java Python Spring
小唐开始学 Spring Boot——(2)Spring Boot核心配置与注解
小唐开始学 Spring Boot——(2)Spring Boot核心配置与注解
|
11天前
|
Java
Springboot 使用自定义注解结合AOP方式校验接口参数
Springboot 使用自定义注解结合AOP方式校验接口参数
Springboot 使用自定义注解结合AOP方式校验接口参数
|
12天前
|
存储 缓存 Java
【JavaEE】Spring中注解的方式去获取Bean对象
【JavaEE】Spring中注解的方式去获取Bean对象
3 0
|
12天前
|
存储 Java 对象存储
【JavaEE】Spring中注解的方式去存储Bean对象
【JavaEE】Spring中注解的方式去存储Bean对象
10 0
|
13天前
|
JSON 前端开发 Java
【JAVA进阶篇教学】第七篇:Spring中常用注解
【JAVA进阶篇教学】第七篇:Spring中常用注解
|
13天前
|
前端开发 安全 Java
使用Spring框架加速Java开发
使用Spring框架加速Java开发
59 0