【Spring源码三千问】没有AspectJ,Spring中如何使用SpringAOP、@Transactional?

【Spring源码三千问】没有AspectJ,Spring中如何使用SpringAOP、@Transactional?,第1张

【Spring源码三千问】没有AspectJ,Spring中如何使用SpringAOP、@Transactional?

没有AspectJ,Spring中如何使用SpringAOP、@Transactional
  • 前言
  • 正文
    • 为什么不加 @EnableAspectJAutoProxy 也能使用 @Transactional ?
    • Spring 风格的 AOP : 定义 PointcutAdvisor 来使用 Spring AOP 功能
      • Spring xml 方式定义 Advisor
      • Spring @Bean 方式定义 Advisor
      • @EnableAspectJAutoProxy 的作用是什么?
    • AutoProxyCreator 自动代理创建者的升级协议
      • AopConfigUtils
  • 小结

系列博文:
【老王读Spring AOP-0】SpringAop引入&&AOP概念、术语介绍
【老王读Spring AOP-1】Pointcut如何匹配到 join point
【老王读Spring AOP-2】如何为 Pointcut 匹配的类生成动态代理
【老王读Spring AOP-3】Spring AOP 执行 Pointcut 对应的 Advice 的过程
【老王读Spring AOP-4】Spring AOP 与Spring IoC 结合的过程 && ProxyFactory 解析
【老王读Spring AOP-5】@Transactional产生AOP代理的原理
【老王读Spring AOP-6】@Async产生AOP代理的原理

相关阅读:
【Spring源码三千问】Spring动态代理:什么时候使用的 cglib,什么时候使用的是 jdk proxy?
【Spring源码三千问】Advice、Advisor、Advised都是什么接口?

前言

Spring AOP 中使用 aspectJ 不是强制的,Spring 实现了 aspectJ 注解风格的 AOP,同时也实现了 Spring 自己风格的 AOP。
只不过, aspectJ 注解的方式来使用 Spring AOP 是最佳实践。

下面,我们就来探索一下:

  1. 没有 aspectJ,Spring AOP 还能正常使用吗?
  2. 没有 aspectJ,我们如何使用 Spring AOP?
正文

前面讲 @Transactional 工作的原理的时候,我们的测试工程的启动类如下:

@SpringBootApplication
@MapperScan("com.kvn.tx.mapper")
@EnableTransactionManagement
@EnableAspectJAutoProxy
public class TxApplication {

    public static void main(String[] args) {
        SpringApplication.run(TxApplication.class, args);
    }
}

如果我们去掉 @EnableAspectJAutoProxy,同时也去掉 aspectjweaver.jar 的依赖,经测试 CarService 也产生了代理类,同样也可以使用 @Transactional 的功能。

我们知道 @Transactional 是通过 Spring AOP 来实现的。这就证明了,如果没有 aspectj,我们也是可以正常使用 Spring AOP 的功能的。

这是为什么呢?下面就来分析一下

为什么不加 @EnableAspectJAutoProxy 也能使用 @Transactional ?

@EnableAspectJAutoProxy 其实是开启 AspectJ 注解风格的 Aspect 时需要添加的。
理论上,我们不加 @EnableAspectJAutoProxy 也是可以使用 Spring AOP 功能的,因为 Spring 并没有完全依赖 AspectJ,只不过使用 AspectJ 注解定义的切面比其他方式更加简洁,而且 AspectJ 注解功能强大。

Spring 中还可以定义 JdkRegexpMethodPointcut 类型的 pointcut。
通常我们都是使用的 AspectJexpressionPointcut 类型的 pointcut。

接下来,我们就再来研究一下:当我们不加 @EnableAspectJAutoProxy 时,@Transactional 标记的类是在哪里产生 AOP 代理类的?

我们首先要找到代理产生的地方。可以在 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization 处添加一个条件断点: condition 是 result != current

public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
        throws BeansException {

    Object result = existingBean;
    for (BeanPostProcessor processor : getBeanPostProcessors()) {
        Object current = processor.postProcessAfterInitialization(result, beanName);
        if (current == null) {
            return result;
        }
        result = current;
    }
    return result;
}

因为 Spring AOP 代理类是在 bean 创建的第三步 initializingBean 时产生的,所以我们将断点打在 AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization 处。
使用条件断点是一个小技巧哦!建议收藏!

通过断点调试,可以发现,在经过 InfrastructureAdvisorAutoProxyCreator 的处理之后,CarService 变成了 AOP 代理类。
也就是说在不加 @EnableAspectJAutoProxy 时,是 InfrastructureAdvisorAutoProxyCreator 这个 BeanPostProcessor 产生的代理类。
而且,这时 application context 中并没有 AnnotationAwareAspectJAutoProxyCreator 这个 BeanPostProcessor。

当我们开启 AspectJ 注解风格的 AOP 时,使用的产生 AOP 代理类的 BeanPostProcessor 是 AnnotationAwareAspectJAutoProxyCreator
当我们使用 Spring 风格的 AOP 时,使用的产生 AOP 代理类的 BeanPostProcessor 是 InfrastructureAdvisorAutoProxyCreator

也就是说,当我们不加 @EnableAspectJAutoProxy 时,其实是使用的 Spring 风格的 AOP。

Spring 风格的 AOP 其实就是定义 Advisor。
Spring 对 AspectJ 风格 AOP 的支持,其实是将 @Aspect 标记的切面转换成了 InstantiationModelAwarePointcutAdvisor。底层原理,还是使用了 Advisor。

Spring 风格的 AOP : 定义 PointcutAdvisor 来使用 Spring AOP 功能

我们可以通过配置 RegexpMethodPointcutAdvisor 来使用 Spring AOP 的功能

Spring xml 方式定义 Advisor

    
    
        
    

Spring @Bean 方式定义 Advisor
@Bean
public RegexpMethodPointcutAdvisor myAdvisor(){
    RegexpMethodPointcutAdvisor advisor = new RegexpMethodPointcutAdvisor();
    
    advisor.setPattern(".*FoooService.*");
    advisor.setAdvice(new MethodBeforeAdvice() {
        @Override
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println("execute before advice:" + method);
        }
    });
    return advisor;
}
@EnableAspectJAutoProxy 的作用是什么?

我们已经搞明白了:
当我们添加 @EnableAspectJAutoProxy 时,其实是使用了 AnnotationAwareAspectJAutoProxyCreator 来产生 AOP 代理类。
而不添加 @EnableAspectJAutoProxy 时,其实是使用了 InfrastructureAdvisorAutoProxyCreator 来产生 AOP 代理类。

而 @Transactional 的功能其实是使用的 Advisor 的方式实现的,没有和 AspectJ 强制绑定,所以,当我们去掉 @EnableAspectJAutoProxy 时,也能正常使用 @Transactional 的功能。

回过头来,我们再来看一下 @EnableAspectJAutoProxy 的作用是什么?

@EnableAspectJAutoProxy 的作用是引入了 @import(AspectJAutoProxyRegistrar.class)。

AspectJAutoProxyRegistrar 的作用是注册 AnnotationAwareAspectJAutoProxyCreator:

class AspectJAutoProxyRegistrar implements importBeanDefinitionRegistrar {

    
    @Override
    public void registerBeanDefinitions(
            Annotationmetadata importingClassmetadata, BeanDefinitionRegistry registry) {

        // 注册 AnnotationAwareAspectJAutoProxyCreator
        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);
            }
        }
    }

}

当使用 @EnableAspectJAutoProxy 之后,就会自动注册 AnnotationAwareAspectJAutoProxyCreator,我们就可以使用 AspectJ 注解风格的 AOP 了。

疑问:
当使用 @EnableAspectJAutoProxy 之后,就自动注册了 AnnotationAwareAspectJAutoProxyCreator,那么它会与 InfrastructureAdvisorAutoProxyCreator 产生冲突吗?
如果这两个同时存在的话,不是会根据 Advisor 产生两次代理?
这样肯定是不行的,那真相究竟是什么?我们就来一起分析一下吧

AutoProxyCreator 自动代理创建者的升级协议

AbstractAdvisorAutoProxyCreator 主要有三个实现类:

  1. InfrastructureAdvisorAutoProxyCreator
  2. AspectJAwareAdvisorAutoProxyCreator
  3. AnnotationAwareAspectJAutoProxyCreator

它们都是根据 Advisor 来产生 AOP 代理类的

通常来说,项目中只需要一个 AutoProxyCreator 就可以了,但是不同的场景下又需要不同的 AutoProxyCreator 来完成。
比如:
场景一:当用户没有添加 aspectj 依赖时,只需要找出 application context 下所有的 advisor 来创建 AOP 代理。
场景二:当用户添加了 aspectj 依赖,并开启了 aspectj 注解切面功能时(@EnableAspectJAutoProxy),就需要找出 application context 下所有的 advisor 和 aspectj 注解风格的切面来创建 AOP 代理类。

为了解决这个问题,Spring 通过 AopConfigUtils 提供了一个简单的升级协议,允许多次调用注册自动代理创建者的方法,但最终只会将更强大 AbstractAdvisorAutoProxyCreator 注册为 BeanPostProcessor。

AopConfigUtils

org.springframework.aop.config.AopConfigUtils: 用于处理AOP自动代理创建者注册的工具类。
AopConfigUtils 只会注册一个自动代理创建者 AutoProxyCreator(即:AbstractAdvisorAutoProxyCreator) 的实现类,注册方法可能会被多次调用,但最终只会注册一个 AutoProxyCreator。

可以看到,源码中定义了三个 AutoProxyCreator:

private static final List> APC_PRIORITY_LIST = new ArrayList<>(3);
static {
        // Set up the escalation list...
        APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
        APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
        APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
        }

自动代理创建者的升级协议:

private static BeanDefinition registerOrEscalateApcAsRequired(
        Class cls, BeanDefinitionRegistry registry, @Nullable Object source) {

    // 升级协议,排在后面的功能更强,优先级更高
    if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
        BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
        if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
            int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
            int requiredPriority = findPriorityForClass(cls);
            if (currentPriority < requiredPriority) {
                apcDefinition.setBeanClassName(cls.getName());
            }
        }
        return null;
    }

    RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
    beanDefinition.setSource(source);
    beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
    beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
    return beanDefinition;
}

可以看出,升级协议的逻辑是:

  1. 第一次调用注册时,registry 中没有,就会直接向 registry 中进行注册
  2. 第二次调用注册时(或者多次调用),会将待注册的 AutoProxyCreator 与 registry 中的进行比较,如果排在 APC_PRIORITY_LIST 的后面,则会将 bean class 进行替换
小结

当添加 @EnableAspectJAutoProxy 时,使用的是 AnnotationAwareAspectJAutoProxyCreator 来产生 AOP 代理类。
不添加 @EnableAspectJAutoProxy 时,使用的是 InfrastructureAdvisorAutoProxyCreator 来产生 AOP 代理类。

InfrastructureAdvisorAutoProxyCreator: 获取 application context 中的 advisor 来产生 AOP 代理类
AnnotationAwareAspectJAutoProxyCreator: 获取 application context 中的 advisor 和 aspectj 注解风格的 Aspect 来产生 AOP 代理类

当我们不依赖 aspectjweaver.jar 时,可以通过定义 Advisor 的方式来使用 Spring AOP 的功能!


如果本文对你有所帮助,欢迎 点赞收藏!
老王读Spring IoC源码分析&测试代码下载
老王读Spring AOP源码分析&测试代码下载

有关 Spring 源码方面的问题欢迎一起交流,备注:CSDN (vx: Kevin-Wang001)

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5563026.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-14
下一篇 2022-12-14

发表评论

登录后才能评论

评论列表(0条)

保存