首先,从一个简单案例说起

UserService.java

  1. @Service
  2. public class UserService {
  3. @Autowired
  4. private UserDao userDao;
  5. @Transactional
  6. public void insertUser(){
  7. userDao.insert();
  8. //otherDao.other();xxx
  9. System.out.println("插入完成...");
  10. int i = 10/0;
  11. }
  12. }

UserDao.java

  1. @Repository
  2. public class UserDao {
  3. @Autowired
  4. private JdbcTemplate jdbcTemplate;
  5. public void insert(){
  6. String sql = "INSERT INTO `tbl_user`(username,age) VALUES(?,?)";
  7. String username = UUID.randomUUID().toString().substring(0, 5);
  8. jdbcTemplate.update(sql, username,19);
  9. }
  10. }

TxConfig.java (注入一个数据库相关的资源,以及事务管理器)

  1. @EnableTransactionManagement
  2. @ComponentScan("cn.spectrumrpc.tx")
  3. @Configuration
  4. public class TxConfig {
  5. //数据源
  6. @Bean
  7. public DataSource dataSource() throws Exception{
  8. ComboPooledDataSource dataSource = new ComboPooledDataSource();
  9. dataSource.setUser("root");
  10. dataSource.setPassword("123456");
  11. dataSource.setDriverClass("com.mysql.jdbc.Driver");
  12. dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
  13. return dataSource;
  14. }
  15. @Bean
  16. public JdbcTemplate jdbcTemplate() throws Exception{
  17. JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
  18. return jdbcTemplate;
  19. }
  20. @Bean
  21. public PlatformTransactionManager transactionManager() throws Exception{
  22. return new DataSourceTransactionManager(dataSource());
  23. }
  24. }

从@EnableTransactionManagement 开始说起

@EnableTransactionManagement 通过@Import导入了一个组件

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Import(TransactionManagementConfigurationSelector.class)
  5. public @interface EnableTransactionManagement {
  6. }

所以,紧接着看 TransactionManagementConfigurationSelector 干了什么事情

首先看这个类的继承图谱

image.png

这个类继承自 AdviceModeImportSelector, 而 AdviceModeImportSelector 又实现了ImportSelector 接口

在 selectImports() 中就会往容器添加一些组件, selectImports 的源码如下。

  1. @Override
  2. protected String[] selectImports(AdviceMode adviceMode) {
  3. switch (adviceMode) {
  4. case PROXY:
  5. return new String[] {AutoProxyRegistrar.class.getName(),
  6. ProxyTransactionManagementConfiguration.class.getName()};
  7. case ASPECTJ:
  8. return new String[] {determineTransactionAspectClass()};
  9. default:
  10. return null;
  11. }
  12. }

在@EnableTransactionManagement 注解上 默认的 AdviceMode 为 PROXY, 所以默认情况下,注册的组件为

  1. AutoProxyRegistrar
  2. ProxyTransactionManagementConfiguration

    1. AdviceMode mode() default AdviceMode.PROXY;

    那么,接下来,我们就好好看看,这两类又干了些什么。

  3. 首先先看 AutoProxyRegistrar,这个类继承自 ImportBeanDefinitionRegistrar,又可以往容器中加一些组件,所以,转向registerBeanDefinitions() 方法。

    1. public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar

    在registerBeanDefinitions() 中,最主要的代码为下面这句,利用BeanDefinitionRegistry ,往容器中,注册一个InfrastructureAdvisorAutoProxyCreator。

    1. AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
    2. // 往容器中添加InfrastructureAdvisorAutoProxyCreator
    3. registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source)

    看 InfrastructureAdvisorAutoProxyCreator 的继承图谱,发现其继承了 AOP 的顶级父类 AbstractAutoProxyCreator

    image.png

    在IOC容器启动时,将会调用后置处理器相应的方法。其中 如果后置处理器的类型是 InstantiationAwareBeanPostProcessor 将会调用 postProcessBeforeInstantiation 前置方法 。 postProcessAfterInitialization 后置方法( 和 AOP的原理一毛一样)

再看 ProxyTransactionManagementConfiguration

  1. BeanFactoryTransactionAttributeSourceAdvisor 注入一个切面,用来增强目标方法
  2. TransactionInterceptor 目标方法的拦截器,在目标方法执行时,将会调用这个拦截器的invoke方法

所以,我们就来看看TransactionInterceptor#invoke

  1. invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
  2. // -> 开启事务,如果需要
  3. TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
  4. // -> 执行目标方法
  5. retVal = invocation.proceedWithInvocation();
  6. // -> catch 如果发生异常,进行回滚
  7. completeTransactionAfterThrowing(txInfo, ex);
  8. // -> 啥事没有,提交事务
  9. commitTransactionAfterReturning(txInfo);

上述的事务提交,以及事务回滚,都是通过调用TransactionManager进行事务管理

  1. public PlatformTransactionManager getTransactionManager() {
  2. Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
  3. return this.transactionManager;
  4. }

在将TransactionInterceptor添加到容器中时,通过下述方法,将PlatformTransactionManager 绑定到了拦截器中,而这个事务管理器是从IOC容器中获取的,所以需要在最开始的配置类中,添加一个 PlatformTransactionManager

  1. interceptor.setTransactionManager(this.txManager)

附录

当我们同时使用@EnableTransactionManagement以及@EnableAspectJAutoProxy时,都知道会导入相应的后置处理器。
在AOP中导入的后置处理器

  1. registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);

在事务中导入的后置处理器

  1. registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source)

可以看出,都是调用 registerOrEscalateApcAsRequired 方法进行的注册

  1. @Nullable
  2. private static BeanDefinition registerOrEscalateApcAsRequired(
  3. Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
  4. Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
  5. // 判断容器中是否有org.springframework.aop.config.internalAutoProxyCreator的Bean定义
  6. // 第一次Enable进来时,不管是谁进来,这个判断都是不存在,就会走到下面去
  7. // 当第二个Enable进来时,这个判断就成立了
  8. if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
  9. // 就会从容器中拿到这个Bean定义
  10. BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
  11. // 判断当前容器中的这个Bean的class是否和我要注册的Bean的class相同
  12. // 因为是事务和aop,所以class肯定不相同
  13. if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
  14. // 就会进入到这边来,寻找这个class对应的优先级,寻找优先级详见下一步
  15. // AOP为2,事务为1
  16. int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
  17. int requiredPriority = findPriorityForClass(cls);
  18. // 判断,将优先级高的后置处理器,放入容器中。
  19. //(假设一开始是事务,后来是AOP。currentPriority=0,requiredPriority=2),这判断成立,把他换成AOP的
  20. // (如果一开始是AOP,后来是事务。currentPriority=2,requiredPriority=0,这个判断不成立,容器中还是AOP)
  21. // 总结,将优先级高的后置处理器放入容器中,即如果同时存在事务和AOP,最终存在的是AOP
  22. if (currentPriority < requiredPriority) {
  23. apcDefinition.setBeanClassName(cls.getName());
  24. }
  25. }
  26. return null;
  27. }
  28. // 第一次进来,创建这个Bean定义,将他注册到容器中
  29. RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
  30. beanDefinition.setSource(source);
  31. beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
  32. beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
  33. registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
  34. return beanDefinition;
  35. }

寻找优先级代码
通过一个 APC_PRIORITY_LIST 来进行优先级的判断,或者到在这个集合中的下标,当作其优先级

  1. private static int findPriorityForClass(@Nullable String className) {
  2. for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {
  3. Class<?> clazz = APC_PRIORITY_LIST.get(i);
  4. if (clazz.getName().equals(className)) {
  5. return i;
  6. }
  7. }
  8. throw new IllegalArgumentException(
  9. "Class name [" + className + "] is not a known auto-proxy creator class");
  10. }

APC_PRIORITY_LIST这个集合,在静态代码块中,进行了初始化赋值
从初始化出来的集合中可以看出,事务导入的后置处理器(_InfrastructureAdvisorAutoProxyCreator)获取出来的为0,AOP导入的后置处理器(AnnotationAwareAspectJAutoProxyCreator)获取出来的为2_

  1. static {
  2. // Set up the escalation list...
  3. APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
  4. APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
  5. APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
  6. }