#yyds干货盘点#老王读Spring AOP-5@Transactional产生AOP代理的原理

著论准过秦,作赋拟子虚。这篇文章主要讲述#yyds干货盘点#老王读Spring AOP-5@Transactional产生AOP代理的原理相关的知识,希望能为你提供帮助。
@TOC
前言通过前面对源码的分析,我们基本了解了整个 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
BeanFactoryTransactionAttributeSourceAdvisorAdvisor 是 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 TransactionAspectSupports invokeWithinTransaction... return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);

#yyds干货盘点#老王读Spring AOP-5@Transactional产生AOP代理的原理

文章图片

可以看出,invokeWithinTransaction() 是带事务执行目标方法,如果目标方法正常返回的话,就会提交事务;如果目标方法抛出异常,则会判断该异常是否需要回滚事务。
invokeWithinTransaction() 的处理流程如下:
  1. 获取待执行方法上的事务属性 TransactionAttribute
    即:方法上的 @Transactional 注解中的配置属性
  2. 选取事务管理器 TransactionManager
  3. 通过TransactionManager开启事务
  4. 执行目标方法
  5. 正常返回,则通过TransactionManager提交事务
    异常返回,则判断是否需要回滚事务
小结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 进行回滚)
如果本文对你有所帮助,欢迎点赞收藏!
【#yyds干货盘点#老王读Spring AOP-5@Transactional产生AOP代理的原理】有关 Spring 源码方面的问题欢迎一起交流,备注:51cto (vx: Kevin-Wang001)
博主好课推荐:
课程 地址
Dubbo源码解读——通向高手之路 https://edu.51cto.com/course/23382.html
正则表达式基础与提升 https://edu.51cto.com/course/16391.html

    推荐阅读