【源码】SpringBoot事务注册原理

发布于:2024-06-06 ⋅ 阅读:(72) ⋅ 点赞:(0)

前言

对于数据库的操作,可能存在脏读、不可重复读、幻读等问题,从而引入了事务的概念。

事务

1.1 事务的定义

事务是指在数据库管理系统中,一系列紧密相关的操作序列,这些操作作为一个单一的工作单元执行。事务的特点是要么全部成功,要么全部失败,不会出现部分完成的情况。如果事务中的任何一个操作失败,那么整个事务都会被回滚到开始之前的状态,以确保数据库的一致性和完整性。

1.2 事务的特性

事务具有4个特性:原子性、一致性、隔离性和持久性。通常称为ACID。

1)原子性(Atomicity)

事务是一个不可分割的工作单位,事务中包含的所有操作要么全部成功,要么全部失败。

2)隔离性(Isolation)

一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的。

3)持久性(Durability)

一旦事务提交成功,则其所做的修改就会永久保存在数据库中,即使发生系统故障也不会丢失。

4)一致性(Consistency)

事务必须确保数据库从一个一致性状态转变到另一个一致性状态。

更准确的说,事务是通过原子性、隔离性和持久性,实现了事务的一致性。另外,一致性还需要额外的工作来保证,如转账,从A转给B,A的资金减少了,B的资金增加了。转账要么成功、要么失败,但不管成功还是失败,事务的一致性要求两人的资金之和必须一致,要么成功,A减少了、B增加了,要么失败,A和B的资金都不变。为了一致性,需要程序来开启事务,同时修改A和B的资金,从而才能保证一致性。

SpringBoot自动装载

在SpringBoot框架中,会自动引入TransactionAutoConfiguration。且在META-INF的spring-autoconfigure-metadata.properties有如下配置:

org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration=
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration$EnableTransactionManagementConfiguration=
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration$EnableTransactionManagementConfiguration.ConditionalOnBean=org.springframework.transaction.TransactionManager

说明在自动引入TransactionAutoConfiguration时,必须存在TransactionManager的bean,且要先引入内部类EnableTransactionManagementConfiguration。

EnableTransactionManagementConfiguration

内部类EnableTransactionManagementConfiguration的源码如下:

public class TransactionAutoConfiguration {
	@Configuration(proxyBeanMethods = false)
	@ConditionalOnBean(TransactionManager.class)
	@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
	public static class EnableTransactionManagementConfiguration {

		@Configuration(proxyBeanMethods = false)
		@EnableTransactionManagement(proxyTargetClass = false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")
		public static class JdkDynamicAutoProxyConfiguration {

		}

		@Configuration(proxyBeanMethods = false)
		@EnableTransactionManagement(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
				matchIfMissing = true)
		public static class CglibAutoProxyConfiguration {

		}

	}
}

EnableTransactionManagementConfiguration内中会自动引入JdkDynamicAutoProxyConfiguration和CglibAutoProxyConfiguration,且添加了@EnableTransactionManagement注解。该注解会自动引入TransactionManagementConfigurationSelector。TransactionManagementConfigurationSelector的父类实现了ImportSelector接口,该类的selectImports()方法返回AutoProxyRegistrar和ProxyTransactionManagementConfiguration类名数组,即AutoProxyRegistrar和ProxyTransactionManagementConfiguration会自动注入到Spring IOC容器中。

Spring的配置类解析的时候,会执行ConfigurationClassParser.processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports),在该方法中,判断importCandidates是否继承于ImportSelector接口,如果是,调用ImportSelector的selectImports()方法,获取需要额外自动加入容器的类。

ProxyTransactionManagementConfiguration

ProxyTransactionManagementConfiguration的源码如下:

package org.springframework.transaction.annotation;

/**
 * Transaction事务管理代理的配置类
 */
@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	/**
	 * 返回一个BeanFactoryTransactionAttributeSourceAdvisor【继承AbstractBeanFactoryPointcutAdvisor,重
	 * 写了getPointcut()方法。即当前Advisor包含了事务需要的advice以及pointcut】
	 * @return
	 */
	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
		// 声明一个BeanFactoryTransactionAttributeSourceAdvisor对象,
		// 传入的transactionAttributeSource为AnnotationTransactionAttributeSource
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource());
		advisor.setAdvice(transactionInterceptor());
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}

	/**
	 * 创建一个AnnotationTransactionAttributeSource对象,该继承AbstractFallbackTransactionAttributeSource,
	 * 对外提供了getTransactionAttribute()方法。该方法返回某个方法的事务注解信息
	 */
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

	/**
	 * 创建一个TransactionInterceptor对象
	 * @return
	 */
	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor() {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource());
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}

}

在ProxyTransactionManagementConfiguration中,自动注入了BeanFactoryTransactionAttributeSourceAdvisor、AnnotationTransactionAttributeSource和TransactionInterceptor。添加了事务处理的advisor,该advisor生效时,会执行TransactionInterceptor拦截器。

BeanFactoryTransactionAttributeSourceAdvisor

BeanFactoryTransactionAttributeSourceAdvisor的源码如下:

package org.springframework.transaction.interceptor;

/**
 * 继承AbstractBeanFactoryPointcutAdvisor,重写了getPointcut()方法。即当前Advisor包含了事务需要的advice以及pointcut
 * 1、维护TransactionAttributeSource对象;
 * 2、创建一个TransactionAttributeSourcePointcut,重写getTransactionAttributeSource(),返回TransactionAttributeSource对
 * 象给TransactionAttributeSourcePointcut,进行方法事务注解判断
 */
@SuppressWarnings("serial")
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

	// 在ProxyTransactionManagementConfiguration类中的transactionAdvisor()方法,
	// 设置transactionAttributeSource为AnnotationTransactionAttributeSource
	@Nullable
	private TransactionAttributeSource transactionAttributeSource;

	private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
		@Override
		@Nullable
		protected TransactionAttributeSource getTransactionAttributeSource() {
			return transactionAttributeSource;
		}
	};

	public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
		this.transactionAttributeSource = transactionAttributeSource;
	}

	public void setClassFilter(ClassFilter classFilter) {
		this.pointcut.setClassFilter(classFilter);
	}

	@Override
	public Pointcut getPointcut() {
		return this.pointcut;
	}

}

在BeanFactoryTransactionAttributeSourceAdvisor切面中,切点为自定义的实现抽象类TransactionAttributeSourcePointcut的对象,抽象方法getTransactionAttributeSource()返回的TransactionAttributeSource对象为ProxyTransactionManagementConfiguration的transactionAdvisor()方法传入的AnnotationTransactionAttributeSource对象。

TransactionAttributeSourcePointcut

TransactionAttributeSourcePointcut的源码如下:

package org.springframework.transaction.interceptor;

/**
 * 抽象类,继承StaticMethodMatcherPointcut,属于静态的方法匹配。在方法匹配中,通过抽象方法getTransactionAttributeSource()获
 * 取TransactionAttributeSource对象,然后执行TransactionAttributeSource.getTransactionAttribute(),判断方法是否有事务注解,
 * 如果有,表示匹配;没有则不匹配
 */
@SuppressWarnings("serial")
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {

	@Override
	public boolean matches(Method method, @Nullable Class<?> targetClass) {
		if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
			return false;
		}
		// 返回AnnotationTransactionAttributeSource
		TransactionAttributeSource tas = getTransactionAttributeSource();
		// 在AnnotationTransactionAttributeSource的getTransactionAttribute()方法中,
		// 获取方法添加的@Transactional注解的信息,如果没有添加@Transactional注解,返回null
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}

	@Override
	public boolean equals(Object other) {
		if (this == other) {
			return true;
		}
		if (!(other instanceof TransactionAttributeSourcePointcut)) {
			return false;
		}
		TransactionAttributeSourcePointcut otherPc = (TransactionAttributeSourcePointcut) other;
		return ObjectUtils.nullSafeEquals(getTransactionAttributeSource(), otherPc.getTransactionAttributeSource());
	}

	@Override
	public int hashCode() {
		return TransactionAttributeSourcePointcut.class.hashCode();
	}

	@Override
	public String toString() {
		return getClass().getName() + ": " + getTransactionAttributeSource();
	}

	/**
	 * 抽象方法,获得一个TransactionAttributeSource对象
	 * @return
	 */
	@Nullable
	protected abstract TransactionAttributeSource getTransactionAttributeSource();

}

TransactionAttributeSourcePointcut继承StaticMethodMatcherPointcut,StaticMethodMatcherPointcut的类匹配默认为ClassFilter.TRUE,即匹配所有的类。

当Spring中的bean对象声明之后,都会调用BeanFactoryTransactionAttributeSourceAdvisor切面,遍历bean的方法,执行切点的matches(Method method, @Nullable Class<?> targetClass)方法,该方法执行如下:

6.1)调用getTransactionAttributeSource(),获取一个TransactionAttributeSource。此处为AnnotationTransactionAttributeSource对象;

6.2)因为TransactionAttributeSource对象不为空,所以执行TransactionAttributeSource的getTransactionAttribute()方法,该方法会执行AnnotationTransactionAttributeSource的父类AbstractFallbackTransactionAttributeSource的getTransactionAttribute()方法,如果方法有返回值,则matches()方法返回true。对应的bean创建代理类,并添加Advisor中的拦截器,即添加TransactionInterceptor;

在该方法中,最终会调用子类AnnotationTransactionAttributeSource的determineTransactionAttribute()方法,遍历事务的解析器,从解析器中获取事务属性信息;结合1)中的描述,会解析org.springframework.transaction.annotation包和javax.transaction包下的@Transactional注解。如果没有@Transactional注解,getTransactionAttribute()最终返回null。matches()会返回false,即不支持,如果有注解,则返回true。对应的bean创建代理类,并添加Advisor中的拦截器,即添加TransactionInterceptor;

AnnotationTransactionAttributeSource

AnnotationTransactionAttributeSource的相关源码如下:

package org.springframework.transaction.annotation;

/**
 * 继承AbstractFallbackTransactionAttributeSource,对外提供了getTransactionAttribute()方法。该方法返回某个方法的事务注解信息
 * 1、添加不同类型的事务注解解析器,用于解析注解信息。支撑jta、ejb和spring的事务
 */
@SuppressWarnings("serial")
public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
		implements Serializable {

	/** 判断包中是否有javax.transaction.Transactional这个类,即项目中是否有对应的包。如果有,则需要添加对应的事务解析器 */
	private static final boolean jta12Present = ClassUtils.isPresent(
			"javax.transaction.Transactional", AnnotationTransactionAttributeSource.class.getClassLoader());

	/** 判断包中是否有javax.ejb.TransactionAttribute这个类,即项目中是否有对应的包。如果有,则需要添加对应的事务解析器 */
	private static final boolean ejb3Present = ClassUtils.isPresent(
			"javax.ejb.TransactionAttribute", AnnotationTransactionAttributeSource.class.getClassLoader());

	/** 标记是否只有public方法才可以添加事务,默认为true */
	private final boolean publicMethodsOnly;

	private final Set<TransactionAnnotationParser> annotationParsers;

	public AnnotationTransactionAttributeSource() {
		this(true);
	}

	/**
	 * 设置publicMethodsOnly的值,并添加事务的注解解析器集合
	 */
	public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
		this.publicMethodsOnly = publicMethodsOnly;
		if (jta12Present || ejb3Present) {
			this.annotationParsers = new LinkedHashSet<>(4);
			// 添加spring的Transactional注解解析器
			this.annotationParsers.add(new SpringTransactionAnnotationParser());
			// 根据条件,添加jta和ejb3两种事务的注解解析器
			if (jta12Present) {
				this.annotationParsers.add(new JtaTransactionAnnotationParser());
			}
			if (ejb3Present) {
				this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
			}
		}
		else {
			// 如果不支持jta和ejb3两种注解的事务,则只添加spring的Transactional注解解析器
			this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
		}
	}

	/**
	 * 调用determineTransactionAttribute()方法,从类中查找事务注解信息
	 */
	@Override
	@Nullable
	protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
		return determineTransactionAttribute(clazz);
	}

	/**
	 * 调用determineTransactionAttribute()方法,从方法中查找事务注解信息
	 */
	@Override
	@Nullable
	protected TransactionAttribute findTransactionAttribute(Method method) {
		return determineTransactionAttribute(method);
	}

	/**
	 * 确定事务属性。遍历事务解析器集合,对当前element进行解析,如果能够正常解析,则返回对应
	 * 的TransactionAttribute【RuleBasedTransactionAttribute对象】;否则返回null
	 */
	@Nullable
	protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
		for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
			TransactionAttribute attr = annotationParser.parseTransactionAnnotation(element);
			if (attr != null) {
				return attr;
			}
		}
		return null;
	}

}

在AnnotationTransactionAttributeSource构造方法中,会添加SpringTransactionAnnotationParser和JtaTransactionAnnotationParser事务注解解析器。

7.1 SpringTransactionAnnotationParser

SpringTransactionAnnotationParser的源码如下:

package org.springframework.transaction.annotation;
/**
 * 实现TransactionAnnotationParser,解析org.springframework.transaction.annotation.Transactional的注解信息,
 * 返回一个RuleBasedTransactionAttribute对象
 */
@SuppressWarnings("serial")
public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {

	/**
	 * 解析@Transaction注解,获取一个TransactionAttribute对象
	 */
	@Override
	@Nullable
	public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
		// 在所提供的element上方的注释层次结构中查找Transactional的第一个注释,
		// 并将该注释的属性与注释层次结构较低级别注释中的匹配的attribute合并
		AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
				element, Transactional.class, false, false);
		// 解析Transactional注解,返回一个RuleBasedTransactionAttribute对象
		if (attributes != null) {
			return parseTransactionAnnotation(attributes);
		}
		else {
			return null;
		}
	}

	public TransactionAttribute parseTransactionAnnotation(Transactional ann) {
		return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));
	}

	/**
	 * 从注解属性对象中,获取事务注解相关属性信息,封装成RuleBasedTransactionAttribute对象
	 */
	protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
		// 根据注解的信息,创建一个RuleBasedTransactionAttribute对象
		RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();

		Propagation propagation = attributes.getEnum("propagation");
		rbta.setPropagationBehavior(propagation.value());
		Isolation isolation = attributes.getEnum("isolation");
		rbta.setIsolationLevel(isolation.value());
		rbta.setTimeout(attributes.getNumber("timeout").intValue());
		rbta.setReadOnly(attributes.getBoolean("readOnly"));
		rbta.setQualifier(attributes.getString("value"));

		// 添加回滚规则
		List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
		for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
			rollbackRules.add(new RollbackRuleAttribute(rbRule));
		}
		for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
			rollbackRules.add(new RollbackRuleAttribute(rbRule));
		}
		for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
			rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
		}
		for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
			rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
		}
		rbta.setRollbackRules(rollbackRules);

		return rbta;
	}


	@Override
	public boolean equals(Object other) {
		return (this == other || other instanceof SpringTransactionAnnotationParser);
	}

	@Override
	public int hashCode() {
		return SpringTransactionAnnotationParser.class.hashCode();
	}

}

SpringTransactionAnnotationParser用于解析org.springframework.transaction.annotation包下的@Transactional的注解信息。

7.2 JtaTransactionAnnotationParser

JtaTransactionAnnotationParser的源码如下:

package org.springframework.transaction.annotation;

/**
 * 实现TransactionAnnotationParser,用于解析javax.transaction.Transactional注解的事务属性。返回一个RuleBasedTransactionAttribute对象
 */
@SuppressWarnings("serial")
public class JtaTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {

	/**
	 * 判断是否有javax.transaction.Transactional,如果有,则进行注解解析【解析传播行为,回滚的异常类、不回滚的异常类设置回滚规则】,
	 * 返回一个RuleBasedTransactionAttribute对象
	 * @param element
	 * @return
	 */
	@Override
	@Nullable
	public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
		AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(
				element, javax.transaction.Transactional.class);
		if (attributes != null) {
			return parseTransactionAnnotation(attributes);
		}
		else {
			return null;
		}
	}

	public TransactionAttribute parseTransactionAnnotation(javax.transaction.Transactional ann) {
		return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));
	}

	protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
		RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();

		// 通过注解的value设定传播行为。默认为REQUIRED
		rbta.setPropagationBehaviorName(
				RuleBasedTransactionAttribute.PREFIX_PROPAGATION + attributes.getEnum("value").toString());

		// 根据设置的回滚的异常类,添加回滚规则
		List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
		for (Class<?> rbRule : attributes.getClassArray("rollbackOn")) {
			rollbackRules.add(new RollbackRuleAttribute(rbRule));
		}
		// 根据设置的不回滚的异常类,添加回滚规则,定义为不回滚
		for (Class<?> rbRule : attributes.getClassArray("dontRollbackOn")) {
			rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
		}
		rbta.setRollbackRules(rollbackRules);

		return rbta;
	}


	@Override
	public boolean equals(Object other) {
		return (this == other || other instanceof JtaTransactionAnnotationParser);
	}

	@Override
	public int hashCode() {
		return JtaTransactionAnnotationParser.class.hashCode();
	}

}

JtaTransactionAnnotationParser用于解析javax.transaction包下的@Transactional注解。

在6.2)中调用AnnotationTransactionAttributeSource的getTransactionAttribute(),最终会调用AnnotationTransactionAttributeSource的determineTransactionAttribute()方法,遍历事务注解的解析器,从解析器中获取事务属性信息。只要方法中添加了org.springframework.transaction.annotation包或javax.transaction包的@Transactional注解,则能够正常获取事务属性信息。

小结

限于篇幅,本篇先分享到这里。以下做一个小结:

1)在SpringBoot框架的项目,项目启动时,会自动开启@EnableTransactionManagement注解,从而自动添加BeanFactoryTransactionAttributeSourceAdvisor切面,添加TransactionAttributeSourcePointcut切点。该切点的ClassFilter为ClassFilter.TRUE,即过滤所有的类。

2)Spring的bean自动注入时,会执行BeanFactoryTransactionAttributeSourceAdvisor切面,遍历bena的方法,执行TransactionAttributeSourcePointcut的matches()。在该方法中,会执行AnnotationTransactionAttributeSource的getTransactionAttribute()方法,判断方法是否添加了org.springframework.transaction.annotation包或javax.transaction包下的@Transactional注解,如果有,则bean的代理类中添加TransactionInterceptor拦截器;

关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。