Spring5源码-事务(AutoProxyRegistrar和ProxyTransactionManagementConfiguration)

本文深入探讨了Spring5中基于注解的事务管理,从@EnableTransactionManagement入口,分析了TransactionManagementConfigurationSelector、AutoProxyRegistrar、InfrastructureAdvisorAutoProxyCreator以及ProxyTransactionManagementConfiguration。特别关注了事务中如何找到潜在的顾问(Advisors)以及为什么事务实现不需要动态生成Advisor。文章揭示了事务管理与AOP的不同之处,解释了事务增强器TransactionInterceptor在处理声明式事务时的关键逻辑。
摘要由CSDN通过智能技术生成

1. 案例(注解版)

  1. 引入依赖 build.gradle文件:
    dependencies {
         api(project(":spring-context"))
         api(project(":spring-aspects"))  //引入aop&切面模块
         api(project(":spring-jdbc"))  //引入jdbc模块
         // https://mvnrepository.com/artifact/c3p0/c3p0
         implementation group: 'c3p0', name: 'c3p0', version: '0.9.1.2'
         // https://mvnrepository.com/artifact/mysql/mysql-connector-java
         implementation group: 'mysql', name: 'mysql-connector-java', version: '8.0.18'
         // https://mvnrepository.com/artifact/org.projectlombok/lombok
         compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.14'
     }

    2.注解版配置文件

@ComponentScan("com.hsf.spring.tx")
@Configuration
@EnableTransactionManagement
public class TxConfig {

   @Bean
   public DataSource dataSource() throws Exception {

      ComboPooledDataSource dataSource = new ComboPooledDataSource();
      dataSource.setUser("root");
      dataSource.setPassword("hsfxuebao");
      dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
      dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/spring_tx");
      return dataSource;
   }

   @Bean
   public JdbcTemplate jdbcTemplate() throws Exception {
      // Spring对@Configuration类会特殊处理,给容器中加组件的方法,多次调用都只是从容器中找组件
      return new JdbcTemplate(dataSource());
   }

   // 注册事务管理器
   @Bean
   public PlatformTransactionManager transactionManager() throws Exception {
      return new DataSourceTransactionManager(dataSource());
   }

}

 3.实例类

@Repository
public class UserDao {

   @Autowired
   private JdbcTemplate jdbcTemplate;

   public void insert() {

      String sql = "INSERT INTO user(name,age) values(?,?)";

      String name = UUID.randomUUID().toString().substring(0, 5);
      jdbcTemplate.update(sql, name, 19);

   }
}

@Service
public class UserInfoService {
   public void test() {
      System.out.println("UserInfoService.test()");
   }
}
@Service
public class UserService {

   @Autowired
   private UserDao userDao;
   // 不自动注入,模拟空指针异常
   private UserInfoService userInfoService;

   @Transactional()
   public void insertUser() {
      userDao.insert();
      System.out.println("插入完成");
      // 模拟空指针异常
      userInfoService.test();
   }
}

4.测试类

public static void main(String[] args) {

   AnnotationConfigApplicationContext context =
         new AnnotationConfigApplicationContext(TxConfig.class);
   // 事务
   UserService userService = context.getBean(UserService.class);
   userService.insertUser();
}

2. @EnableTransactionManagement

我们第1小节中开始事务管理很简单,使用 @EnableTransactionManagement 注解即可。那么也就说明 @EnableTransactionManagement 是我们分析的入口了。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

	boolean proxyTargetClass() default false;

	AdviceMode mode() default AdviceMode.PROXY;

	int order() default Ordered.LOWEST_PRECEDENCE;

}

很明显了 @Import(TransactionManagementConfigurationSelector.class) 指向我们去看 去看 TransactionManagementConfigurationSelector 的实现。

2.1 TransactionManagementConfigurationSelector

可以看到, TransactionManagementConfigurationSelector 间接实现了 ImportSelector 接口, ImportSelector 会根据 selectImports 返回的字符串数组(一般是类的全路径名) 通过 反射加载该类并注册到Spring容器中 。

所以我们这里必然来看一下 selectImports 方法了, ImportSelector#selectImports 的实现在其父类 AdviceModeImportSelector#selectImports :

@Override
public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // 获取注解类型, 这里是 EnableTransactionManagement
        Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
        Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");
        // 解析出 @EnableTransactionManagement 注解的参数
        AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
        if (attributes == null) {
                throw new IllegalArgumentException(String.format(
                                "@%s is not present on importing class '%s' as expected",
                                annType.getSimpleName(), importingClassMetadata.getClassName()));
        }
        // 获取mode属性。EnableTransactionManagement 默认mode =  AdviceMode.PROXY
        AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
        // 调用 TransactionManagementConfigurationSelector#selectImports
        String[] imports = selectImports(adviceMode);
        if (imports == null) {
                throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
        }
        return imports;
}
...
        @Nullable
protected abstract String[] selectImports(AdviceMode adviceMode);

 可以知道了 这里是将 protected abstract String[] selectImports(AdviceMode adviceMode); 返回的值返回给 Spring。这里我们看看在 TransactionManagementConfigurationSelector 中的 selectImports(AdviceMode adviceMode) 方法的实现。

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		// 默认值 是 PROXY。个人猜测是通过 代理模式实现事务,如果是 ASPECTJ 则是通过 ASPECTJ的方式实现,AspectJ 需要单独引入编译
		switch (adviceMode) {
			case PROXY:
				return new String[] {AutoProxyRegistrar.class.getName(),
						ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {determineTransactionAspectClass()};
			default:
				return null;
		}
	}

	private String determineTransactionAspectClass() {
		return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
				TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
				TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
	}

}

到这里就可以看到了,默认情况下,我们引入了两个类, AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration 。

  • AutoProxyRegistrar : 主要是注册了 InfrastructureAdvisorAutoProxyCreator 自动代理创建器。而 InfrastructureAdvisorAutoProxyCreator 的逻辑基本上和 Aop 的逻辑相同
  • ProxyTransactionManagementConfiguration : 注册了事务实现的核心 Bean,包括 BeanFactoryTransactionAttributeSourceAdvisor 、 TransactionAttributeSource 、 TransactionInterceptor 等

3. AutoProxyRegistrar

AutoProxyRegistrar 实现了 ImportBeanDefinitionRegistrar 接口,所以我们要去看看他的 registerBeanDefinitions 方法的实现。

AutoProxyRegistrar#registerBeanDefinitions 代码如下:

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean candidateFound = false;
        // 获取 当前类上的所有注解
        Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
        for (String annType : annTypes) {
                // 获取注解的所有属性
                AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
                if (candidate == null) {
                        continue;
                }
                // 获取mode、proxyTargetClass 属性
                Object mode = candidate.get("mode");
                Object proxyTargetClass = candidate.get("proxyTargetClass");
                if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
                                Boolean.class == proxyTargetClass.getClass()) {
                        candidateFound = true;
                        // 判断如果是 Proxy 模式,也就是默认模式,注册自动代理创建器
                        if (mode == AdviceMode.PROXY) {
                                AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                                // 如果需要代理目标列,则强制自动代理创建者使用类代理
                                if ((Boolean) proxyTargetClass) {
                                        AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                                        return;
                                }
                        }
                }
        }
        ... 省略日志打印
}

在这里我们可以看到, registerBeanDefinitions 方法中解析了 事务注解 ,并 注册了自动代理创建器 。这里自动代理创建器我们在Aop 源码中提到过,是Aop 创建的核心。

AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry) 这一步最主要的作用将自动代理创建器 InfrastructureAdvisorAutoProxyCreator 注册到了 Spring容器中。

经过数

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值