SpringBoot---事务实现原理

一、前言

利用SpringBoot实现事务非常简单,主要有以下两步骤:

1.在启动类上加注解@EnableTransactionManagement

2.在需要事务管理的方法上添加注解@Transactional

简单的代码后面却体现了SpringAOP的思想和精髓,接下来我们先思考一下可能的实现方式。

二、思考

要对一个方法进行事务管理,肯定要对该方法进行增强,那就有以下几个问题:

1.如何增强

我们知道动态代理和切面都是是可以的。那么假如用代理,代理的逻辑在哪里,即开启事务,提交事务的逻辑在哪里。

2.何时对该方法进行增强

在博文Spring---ApplicationContext的Refresh分析+hook函数分析我们了解到Spring在Bean创建的过程中提供了很多钩子函数。那是否可以在Bean初始化完成之后利用钩子函数对Bean进行代理呢。

三、分析

3.1 @EnableTransactionManagement解析

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

在前面几篇Spring系列文章中,我们了解到Spring启动时主要借助ConfigurationClassPostProcessor扫描程序中所有定义的Bean添加到BeanDefinitionMap之中。我们再来看下该类是怎么做的。

3.1.1 将所有标注有@Component、@Configuration等注解的类添加到BeanDefinitionMap并解析为ConfigurationClass

对于ConfigurationClass类我们有必要了解一下:

final class ConfigurationClass {
    //该类的注解信息
	private final AnnotationMetadata metadata;
    //该类.class文件路径
	private final Resource resource;
    //该类代表的bean名称
	@Nullable
	private String beanName;
    //该类是被哪个类通过@Import注解导入进来的
	private final Set<ConfigurationClass> importedBy = new LinkedHashSet<>(1);
    //该Configuration类中具有@Bean注解的方法(这些方法在后续会被解析为Bean)
	private final Set<BeanMethod> beanMethods = new LinkedHashSet<>();
    //该类要导入的资源(一般是.xml文件描述的bean)
	private final Map<String, Class<? extends BeanDefinitionReader>> importedResources =
			new LinkedHashMap<>();
    //该类要直接注册的BeanDefinition,后面就会看到@EnableTransationManagement怎么使用它的
	private final Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars =
			new LinkedHashMap<>();
	final Set<String> skippedBeanMethods = new HashSet<>();

ok,步入正题。

ConfigurationClassPostProcessor在解析我们的启动类时,最终会调用org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass方法进行解析,此处不了解的可以看博文Spring---组件扫描过程。该类会依次解析@PropertyResource注解、@ComponentScan注解、@Import注解等等。本文的主角就是@Import注解。

@Import注解收集

//org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass

// Process any @Import annotations 296行
processImports(configClass, sourceClass, getImports(sourceClass), true);

首先获取通过getImports方法手机@import注解要导入的所有类

//org.springframework.context.annotation.ConfigurationClassParser#getImports

//sourceClass即我们的启动类BootApplication
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException {
	Set<SourceClass> imports = new LinkedHashSet<>();
	Set<SourceClass> visited = new LinkedHashSet<>();
	collectImports(sourceClass, imports, visited);
	return imports;
}
//org.springframework.context.annotation.ConfigurationClassParser#collectImports
private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited)
		throws IOException {

    //递归扫描启动类的所有注解
	if (visited.add(sourceClass)) {
		for (SourceClass annotation : sourceClass.getAnnotations()) {
			String annName = annotation.getMetadata().getClassName();
			if (!annName.startsWith("java") && !annName.equals(Import.class.getName())) {
				collectImports(annotation, imports, visited);
			}
		}
        //如果注解为@Import,则将其Value收集
		imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value"));
	}
}

通过上面分析,我们再来看@EnableTransactionManagement注解,其上的TransactionManagementConfigurationSelector类将会被收集进行分析。接下来,我们看下如何处理收集到的这个注解。

@Import注解处理

//org.springframework.context.annotation.ConfigurationClassParser#processImports

//configClass和currentSourceClass目前都是BootApplication
//importCandidates是我们刚收集到的@Import注解的value值

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
		Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {

	if (importCandidates.isEmpty()) {
		return;
	}

	if (checkForCircularImports && isChainedImportOnStack(configClass)) {
		this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
	}
	else {
		this.importStack.push(configClass);
		try {
            //循环处理我们收集到的@Import信息,其主要分三类进行处理,
            //1.ImportSelector
            //2.ImportBeanDefinitionRegistrar
            //3.其他的作为@Configuration类处理
			for (SourceClass candidate : importCandidates) {
				//处理逻辑请看下文
			}
		}
		catch (BeanDefinitionStoreException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanDefinitionStoreException(
					"Failed to process import candidates for configuration class [" 
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot是一个用于构建Java应用程序的开源框架,它简化了Spring应用程序的开发过程。事务Spring Boot中非常重要的一个特性,它可以确保数据库操作的一致性和完整性。下面是Spring Boot事务底层原理的介绍: Spring Boot使用了Spring框架中的事务管理器来实现事务功能。事务管理器是一个接口,它定义了一些方法来管理事务的开始、提交和回滚等操作。在Spring Boot中,常用的事务管理器有两种:JpaTransactionManager和DataSourceTransactionManager。 JpaTransactionManager是用于管理JPA(Java Persistence API)事务事务管理器。它通过与JPA提供商(如Hibernate)进行交互,来实现对数据库的事务管理。 DataSourceTransactionManager是用于管理传统的关系型数据库(如MySQL、Oracle等)事务事务管理器。它通过与数据源进行交互,来实现对数据库的事务管理。 在Spring Boot中,我们可以通过在方法上添加@Transactional注解来启用事务。当方法被调用时,Spring会自动创建一个事务,并在方法执行结束后根据方法的执行结果来决定是提交事务还是回滚事务事务的隔离级别、传播行为等属性可以通过@Transactional注解的属性来进行配置。例如,可以设置隔离级别为READ_COMMITTED,传播行为为REQUIRED等。 总结一下,Spring Boot的事务底层原理是通过事务管理器来管理事务的开始、提交和回滚等操作。我们可以通过@Transactional注解来启用事务,并通过注解的属性来配置事务的属性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值