spring事务原理和事务同步器使用简介

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
复制代码

加入依赖之后,自动化配置类将自动配置启用事务的类对象

@Configuration
// 引入 spring-boot-starter-jdbc 之后,类路径才存在 PlatformTransactionManager,配置生效
@ConditionalOnClass(PlatformTransactionManager.class)
@AutoConfigureAfter({ JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
		DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class })
@EnableConfigurationProperties(TransactionProperties.class)
public class TransactionAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean
	public TransactionManagerCustomizers platformTransactionManagerCustomizers(
			ObjectProvider<PlatformTransactionManagerCustomizer<?>> customizers) {
		return new TransactionManagerCustomizers(customizers.orderedStream().collect(Collectors.toList()));
	}

	@Configuration
	@ConditionalOnSingleCandidate(PlatformTransactionManager.class)
	public static class TransactionTemplateConfiguration {

		private final PlatformTransactionManager transactionManager;

		public TransactionTemplateConfiguration(PlatformTransactionManager transactionManager) {
			this.transactionManager = transactionManager;
		}

		@Bean
		@ConditionalOnMissingBean(TransactionOperations.class)
		public TransactionTemplate transactionTemplate() {
			return new TransactionTemplate(this.transactionManager);
		}

	}

	@Configuration
	@ConditionalOnBean(PlatformTransactionManager.class)
	@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
	public static class EnableTransactionManagementConfiguration {

        // 启用事务
		@Configuration
		@EnableTransactionManagement(proxyTargetClass = false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
				matchIfMissing = false)
		public static class JdkDynamicAutoProxyConfiguration {

		}

        // 启用事务。没有配置 spring.aop.proxy-target-class 时,默认使用的 proxyTargetClass = true。使用CGLIB来生成代理
		@Configuration
		@EnableTransactionManagement(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
				matchIfMissing = true)
		public static class CglibAutoProxyConfiguration {

		}

	}

}
复制代码

配置加载

当引入依赖后,自动化配置类 TransactionAutoConfiguration 生效。其实现又将引入以下配置

  • AutoProxyRegistrar:ImportBeanDefinitionRegistrar 实现类,容器启动时回调其registerBeanDefinitions方法,以便引入更细化的配置
    • InfrastructureAdvisorAutoProxyCreator 由于优先级比 AnnotationAwareAspectJAutoProxyCreator 低,因此并未生效
  • ProxyTransactionManagementConfiguration @Configuration标记的配置类
    • BeanFactoryTransactionAttributeSourceAdvisor
      • 内部的pointvut属性为:TransactionAttributeSourcePointcut
    • AnnotationTransactionAttributeSource 读取@Transactional属性值,暴露给 spring 事务框架
    • TransactionInterceptor
    • TransactionalEventListenerFactory

如何构造出带事务的代理类

BeanFactoryTransactionAttributeSourceAdvisor、AnnotationTransactionAttributeSource、TransactionInterceptor的类结构图。

首先要清楚几个概念:

  • ClassFilter、MethodMatcher 共同实现了「判断是否拦截方法」的能力
  • Pointcut,组合ClassFilter、MethodMatcher,用于识别是否对一个类方法进行增强
  • Advice,承载增强能力的标签类
  • Advisor,承载AOP中的advice、pointcut能力的类

构造流程时序

通过 AnnotationAwareAspectJAutoProxyCreator 进行代理对象的生成,其原理就是在进行IOC容器的初始化时,初始化bean都会回调 BeanPostProcessor.postProcessAfterInitialization 方法。也就是在这时进行代理对象的生成。

在生成过程中,会寻找 IOC 容器中的 Advisor,在启用事务控制之后,默认有 BeanFactoryTransactionAttributeSourceAdvisor ,将通过 ProxyFactory 创建代理对象:CglibAopProxy 或者 JdkDynamicAopProxy,代理对象的实现根据 spring.aop.proxy-target-class 属性和被代理类是否为接口来决定。默认情况下,使用CglibAopProxy。

切入事务管理的执行流程

事务回滚

事务提交

与事务管理流程相关的类:

  • TransactionAttribute - DelegatingTransactionAttribute
  • PlatformTransactionManager - DataSourceTransactionManager
  • TransactionStatus
  • TransactionInfo
  • ConnectionHolder

在整个事务管理的流程中,主要通过 TransactionInterceptor 根据异常与否来切入提交、回滚的功能。由DataSourceTransactionManager封装提交、回滚两个操作的门面接口供TransactionInterceptor调用,在 DataSourceTransactionManager 内部,其内部封装了 TransactionStatus,而TransactionStatus 包含着的TransactionObject可以通过其 ConnectionHolder 来获取当前所用连接对象,进而执行提交或回滚;

除此之外,spring 还提供了 TransactionSynchronization 作为事务同步器,在「提交前、回滚前、提交后、回滚后、执行回滚(或提交)完成 」这几个时机进行同步器的回调。

用法如下

@Transactional(rollbackFor = Exception.class)
@Override
public Author save(Author author) {
    jdbcTemplate.update("insert into author(name) values (?)", author.getName());
	// 注册事务同步器,在事务提交后进行回调
    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
        @Override
        public void afterCommit() {
            System.out.println("after commit...");
        }
    });
    return author;
}
复制代码
我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章