【老王读Spring AOP-5】@Transactional产生AOP代理的原理

前言

通过前面对源码的分析,我们基本了解了整个 AOP 代理生产的过程:

  1. 找到与 bean 匹配的所有的 Advisor
  2. 使用所有匹配的 Advisor 来为 bean 生成生成动态代理
  3. 通过动态代理类执行 Advice
  4. 将 Spring AOP 与 Spring IoC 进行结合

我们知道 Spring 的事务管理也是通过 AOP 来实现的。接下来,我们就通过前面所积累的知识来分析一下: Spring 中的 @Transactional 是如何工作的?

版本约定

Spring 5.3.9 (通过 SpringBoot 2.5.3 间接引入的依赖)

正文

前面分析 如何为 Pointcut 匹配的类生成动态代理类 时,我们发现,Spring 是在 bean 创建时的第三步 initializeBean 时,调用 AnnotationAwareAspectJAutoProxyCreator#postProcessAfterInitialization() 来产生代理 bean 的。

说的更具体点,是在调用父类的 AbstractAutoProxyCreator#wrapIfNecessary() 方法时,获取到与 bean 匹配的 Advisor,通过 ProxyFactory 来创建的代理类。

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}

// AbstractAutoProxyCreator#wrapIfNecessary()
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    ......

    // Create proxy if we have advice.
    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
    if (specificInterceptors != DO_NOT_PROXY) {
        this.advisedBeans.put(cacheKey, Boolean.TRUE);
        // 创建代理 bean  
        Object proxy = createProxy(
                bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);
    return bean;
}

接下来,我们就通过 AnnotationAwareAspectJAutoProxyCreator 这条线索,来分析一下含有 @Transactional 的类是如何产生 AOP 代理类的?

准备一个干净极简的工程

首先,我们先准备一下干净极简的工程, 创建一个 CarService,含有一个 @Transactional 方法,让这个最简单的工程 run 起来。

@Service
public class CarService {
    @Autowired
    private CarMapper carMapper;

    @Transactional
    public void insertWithTx(Car car){
        carMapper.insert(car);
        throw new RuntimeException("出错啦");
    }
}

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

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

准备干净极简的工程的目的是让我们的代码环境尽量的简单,方便我们针对单一特性来做研究,排除不些不必要的干扰项

通过源码处的条件断点来研究

我们直接在 AbstractAutoProxyCreator#wrapIfNecessary() 方法中创建代理处打一个断点。
可以发现,匹配到的 Advisor 是: BeanFactoryTransactionAttributeSourceAdvisor

我们再看一下 BeanFactoryTransactionAttributeSourceAdvisor 被引用的地方,可以发现是在 ProxyTransactionManagementConfiguration 中。
而 ProxyTransactionManagementConfiguration 被引用的地方则是 @EnableTransactionManagement

ProxyTransactionManagementConfiguration 具体的配置类如下:

@Configuration(proxyBeanMethods = false)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

    @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
            TransactionAttributeSource transactionAttributeSource,
            TransactionInterceptor transactionInterceptor) {
        // 使用的 pointcut 是: TransactionAttributeSourcePointcut  
        BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
        // TransactionAttributeSource 是用来获取事务元数据的
        advisor.setTransactionAttributeSource(transactionAttributeSource);
        // 针对 @Transactional 使用的 Advice 
        advisor.setAdvice(transactionInterceptor);
        if (this.enableTx != null) {
            advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
        }
        return advisor;
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionAttributeSource transactionAttributeSource() {
        return new AnnotationTransactionAttributeSource();
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionInterceptor transactionInterceptor(
            TransactionAttributeSource transactionAttributeSource) {
        TransactionInterceptor interceptor = new TransactionInterceptor();
        interceptor.setTransactionAttributeSource(transactionAttributeSource);
        if (this.txManager != null) {
            // 设置事务管理器
            interceptor.setTransactionManager(this.txManager);
        }
        return interceptor;
    }

}

通过 ProxyTransactionManagementConfiguration 的配置,我们可以看出,它定义了 advisor : BeanFactoryTransactionAttributeSourceAdvisor

BeanFactoryTransactionAttributeSourceAdvisor

Advisor 是 Spring AOP 产生代理类的关键配置,它包含了 pointcut 和 advice。(通常是 PointcutAdvisor)
pointcut 用于匹配 bean,对应的 advice 用于通知。

BeanFactoryTransactionAttributeSourceAdvisor 中包含的 pointcut 和 advice:

  • pointcut :
    TransactionAttributeSourcePointcut 用于匹配 @Transactional 标记的方法对应的类(或者直接被 @Transactional 标记的类)
  • advice:
    TransactionInterceptor 用于处理事务方法的执行拦截

TransactionInterceptor

事务的开启和提交,都是通过 TransactionInterceptor#invoke() 来进行拦截处理的。

// TransactionInterceptor#invoke()
public Object invoke(MethodInvocation invocation) throws Throwable {
    // Work out the target class: may be {@code null}.
    // The TransactionAttributeSource should be passed the target class
    // as well as the method, which may be from an interface.
    Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

    // Adapt to TransactionAspectSupport's invokeWithinTransaction...
    return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

invokeWithinTransaction

可以看出,invokeWithinTransaction() 是带事务执行目标方法,如果目标方法正常返回的话,就会提交事务;如果目标方法抛出异常,则会判断该异常是否需要回滚事务。

invokeWithinTransaction() 的处理流程如下:

  1. 获取待执行方法上的事务属性 TransactionAttribute
    即:方法上的 @Transactional 注解中的配置属性
  2. 选取事务管理器 TransactionManager
  3. 通过TransactionManager开启事务
  4. 执行目标方法
  5. 正常返回,则通过TransactionManager提交事务
    异常返回,则判断是否需要回滚事务

Spring 对事务的封装,后续再进行详细分析,这里主要分析 @Transactional 工作的过程

小结

Spring 使用 Spring AOP 框架来为 @Transactional 标记的类或方法产生 AOP 代理类的方式来处理事务方法。
具体是定义了一个 Advisor : BeanFactoryTransactionAttributeSourceAdvisor,来拦截 @Transactional 方法。

BeanFactoryTransactionAttributeSourceAdvisor 中包含的 pointcut 和 advice:

  • pointcut :
    TransactionAttributeSourcePointcut 用于匹配 @Transactional 标记的方法对应的类(或者直接被 @Transactional 标记的类)
  • advice:
    TransactionInterceptor 用于处理事务方法的执行拦截

TransactionInterceptor#invoke() 会调用父类的 invokeWithinTransaction() 方法来完成事务方法的执行。
invokeWithinTransaction() 的处理流程如下:

  1. 获取待执行方法上的事务属性 TransactionAttribute
    即:方法上的 @Transactional 注解中的配置属性
  2. 选取事务管理器 TransactionManager
  3. 通过TransactionManager开启事务
  4. 执行目标方法
  5. 正常返回,则通过TransactionManager提交事务
    异常返回,则判断是否需要回滚事务(默认对 RuntimeException 和 Error 进行回滚)

Spring 中是通过 TransactionManager 来管理事务的


如果本文对你有所帮助,欢迎点赞收藏!

源码测试工程下载:
老王读Spring IoC源码分析&测试代码下载
老王读Spring AOP源码分析&测试代码下载

公众号后台回复:下载IoC 或者 下载AOP 可以免费下载源码测试工程…

阅读更多文章,请关注公众号: 老王学源码
gzh


系列博文:
【老王读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 IoC、AOP 原理小总结

相关阅读:
【Spring源码三千问】Spring动态代理:什么时候使用的 cglib,什么时候使用的是 jdk proxy?
【Spring源码三千问】Advice、Advisor、Advised都是什么接口?
【Spring源码三千问】没有AspectJ,Spring中如何使用SpringAOP、@Transactional?
【Spring源码三千问】Spring AOP 中 AbstractAdvisorAutoProxyCreator、AbstractAdvisingBeanPostProcessor的区别
【Spring 源码三千问】同样是AOP代理bean,为什么@Async标记的bean循环依赖时会报错?

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老王学源码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值