今天我们来看下spring 的 tx 模块的核心流程。
1. 实例
配置一个启动事务管理类,配置一个数据源事务管理器:
@Configuration
@EnableTransactionManagement
static class DefaultTxManagerNameConfig {
@Bean
PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
配置一个数据源、JdbcFooRepository 类
@Configuration
static class Config {
@Bean
FooRepository fooRepository() {
JdbcFooRepository repos = new JdbcFooRepository();
repos.setDataSource(dataSource());
return repos;
}
@Bean
DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.build();
}
}
基础的 DAO 类,在 findAll() 方法上标注 @Transactional 注解
interface FooRepository {
List<Object> findAll();
}
static class JdbcFooRepository implements FooRepository {
public void setDataSource(DataSource dataSource) {
}
@Override
@Transactional
public List<Object> findAll() {
ArrayList<Object> result = new ArrayList<>();
for (int i1 = 0; i1 < 10; i1++) {
int random = (int) (Math.random() * 100);
result.add(random);
}
return result;
}
}
最后配置一个测试类:
public class EnableTransactionManagementIntegrationTests {
@Test
void repositoryIsTxProxy_withDefaultTxManagerName() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class, DefaultTxManagerNameConfig.class);
FooRepository repo = ctx.getBean(FooRepository.class);
List<Object> all = repo.findAll();
System.out.println("all = " + all);
}
}
这样就配置了一个使用事务注解支持事务的方法的例子了。
2. 分析
我们从 DefaultTxManagerNameConfig 上的 @EnableTransactionManagement 开始看:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
/**
* 指定使用什么代理模式(true 为 cglib 代理,false 为 jdk 代理)
*
* Indicate whether subclass-based (CGLIB) proxies are to be created ({@code true}) as
* opposed to standard Java interface-based proxies ({@code false}). The default is
* {@code false}. <strong>Applicable only if {@link #mode()} is set to
* {@link AdviceMode#PROXY}</strong>.
* <p>Note that setting this attribute to {@code true} will affect <em>all</em>
* Spring-managed beans requiring proxying, not just those marked with
* {@code @Transactional}. For example, other beans marked with Spring's
* {@code @Async} annotation will be upgraded to subclass proxying at the same
* time. This approach has no negative impact in practice unless one is explicitly
* expecting one type of proxy vs another, e.g. in tests.
*/
boolean proxyTargetClass() default false;
/**
* 通知的模式,代理模式或者 aspectj,一般是使用代理模式。
* 注意代理模式只允许调用拦截,通过在本类中的本地调用不能被拦截;
* 一个 Transactional 注解在一个本地调用的方法上将会被 spring 的拦截器忽略,甚至不会再这种场景中出现。
* 对于拦截更多高级
*
* Indicate how transactional advice should be applied.
* <p><b>The default is {@link AdviceMode#PROXY}.</b>
* Please note that proxy mode allows for interception of calls through the proxy
* only. Local calls within the same class cannot get intercepted that way; an
* {@link Transactional} annotation on such a method within a local call will be
* ignored since Spring's interceptor does not even kick in for such a runtime
* scenario. For a more advanced mode of interception, consider switching this to
* {@link AdviceMode#ASPECTJ}.
*/
AdviceMode mode() default AdviceMode.PROXY;
/**
* Indicate the ordering of the execution of the transaction advisor
* when multiple advices are applied at a specific joinpoint.
* <p>The default is {@link Ordered#LOWEST_PRECEDENCE}.
*/
int order() default Ordered.LOWEST_PRECEDENCE;
}
这个类有三个属性,proxyTargetClass、mode、order,分别表示:是否使用 cglib 代理、通知的模式(PROXY 或者 ASPECTJ)、排序。
它还使用了 @Import(TransactionManagementConfigurationSelector.class) 注解,导入了 TransactionManagementConfigurationSelector 类:
/**
* 在导入 @Configuration 注解类时候,根据选择 EnableTransactionManagement 的 mode,来选择
* AbstractTransactionManagementConfiguration 类合适的子类,
*
* Selects which implementation of {@link AbstractTransactionManagementConfiguration}
* should be used based on the value of {@link EnableTransactionManagement#mode} on the
* importing {@code @Configuration} class.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
* @see EnableTransactionManagement
* @see ProxyTransactionManagementConfiguration
* @see TransactionManagementConfigUtils#TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME
* @see TransactionManagementConfigUtils#JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME
*/
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
/**
* Returns {@link ProxyTransactionManagementConfiguration} or
* {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY}
* and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()},
* respectively.
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
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);
}
}
看下它的类图结构:
这个类继承了 AdviceModeImportSelector 类,它是一个 ImportSelector 导入选择器,重写了 selectImports() 方法,通过 adviceMode 来返回一组类的名称,我们一般使用 AdviceMode.PROXY,可以看到它会返回 AutoProxyRegistrar.classs 和 ProxyTransactionManagementConfiguration.class 这两个类的名称。
我们回顾下 ImportSelector 类,它的 selectImports() 方法是在 org.springframework.context.annotation.ConfigurationClassParser#processImports 中进行调用的。它是在 spring 容器启动时,执行 bean 工厂注册器后置处理器时,调用了 ConfigurationClassParser 配置类解析器的解析扫描 @Configuration 注解的类的 bean 定义流程中执行的。
2.1 AutoProxyRegistrar
接着继续看 AutoProxyRegistrar.classs 这个类,它的类图:
它实现为:
/**
* 针对当前的 BeanDefinitionRegistry 作为一个合适的基于 @Enable* 注解标有 mode 和 proxyTargetClass 的属性,
* 设置到正确的值。
*
* Registers an auto proxy creator against the current {@link BeanDefinitionRegistry}
* as appropriate based on an {@code @Enable*} annotation having {@code mode} and
* {@code proxyTargetClass} attributes set to the correct values.
*
* @author Chris Beams
* @since 3.1
* @see org.springframework.cache.annotation.EnableCaching
* @see org.springframework.transaction.annotation.EnableTransactionManagement
*/
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
private final Log logger = LogFactory.getLog(getClass());
/**
* 注册bean 定义
*
* Register, escalate, and configure the standard auto proxy creator (APC) against the
* given registry. Works by finding the nearest annotation declared on the importing
* {@code @Configuration} class that has both {@code mode} and {@code proxyTargetClass}
* attributes. If {@code mode} is set to {@code PROXY}, the APC is registered; if
* {@code proxyTargetClass} is set to {@code true}, then the APC is forced to use
* subclass (CGLIB) proxying.
* <p>Several {@code @Enable*} annotations expose both {@code mode} and
* {@code proxyTargetClass} attributes. It is important to note that most of these
* capabilities end up sharing a {@linkplain AopConfigUtils#AUTO_PROXY_CREATOR_BEAN_NAME
* single APC}. For this reason, this implementation doesn't "care" exactly which
* annotation it finds -- as long as it exposes the right {@code mode} and
* {@code proxyTargetClass} attributes, the APC can be registered and configured all
* the same.
*/
@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;
}
// 获取模式
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;
// 使用代理模式
if (mode == AdviceMode.PROXY) {
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
// 强制自动代理创建器使用类代理,proxyTargetClass
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
if (!candidateFound && logger.isInfoEnabled()) {
String name = getClass().getSimpleName();
logger.info(String.format("%s was imported but no annotations were found " +
"having both 'mode' and 'proxyTargetClass' attributes of type " +
"AdviceMode and boolean respectively. This means that auto proxy " +
"creator registration and configuration may not have occurred as " +
"intended, and components may not be proxied as expected. Check to " +
"ensure that %s has been @Import'ed on the same class where these " +
"annotations are declared; otherwise remove the import of %s " +
"altogether.", name, name, name));
}
}
}
它是一个 ImportBeanDefinitionRegistrar 类型,导入 bean 定义注册器,实现了 registerBeanDefinitions() 方法,这个方法做的事情:
- 获取导入类的注解元数据;
- 获取 mode 注解属性、proxyTargetClass 注解属性;
- 根据它们的值,注册一个名称为 org.springframework.aop.config.internalAutoProxyCreator,值为 InfrastructureAdvisorAutoProxyCreator 类型的 bean 定义;
- 以及bean 定义的 proxyTargetClass 属性。
它的这个方法是在 org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsFromRegistrars 处调用的,也是属于配置类后置处理器注册已经将 bean 定义解析为配置类的流程中。
2.2 InfrastructureAdvisorAutoProxyCreator
看下 InfrastructureAdvisorAutoProxyCreator 类,它的类图:
它的实现:
/**
* 自动代理创建器,仅仅考虑基础的增强器 beans,忽略其他应用程序定义的增强器
*
* Auto-proxy creator that considers infrastructure Advisor beans only,
* ignoring any application-defined Advisors.
*
* @author Juergen Hoeller
* @since 2.0.7
*/
@SuppressWarnings("serial")
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {
@Nullable
private ConfigurableListableBeanFactory beanFactory;
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
this.beanFactory = beanFactory;
}
@Override
protected boolean isEligibleAdvisorBean(String beanName) {
// 判断是否是一个合格的增强器,@Role(BeanDefinition.ROLE_INFRASTRUCTURE) bean 定义的角色是基础类
return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&
this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
}
}
这个类它和 spring aop 中的 AnnotationAwareAspectJAutoProxyCreator 类很像,没错!它们都是共同继承了 AbstractAdvisorAutoProxyCreator 类型,间接的实现了 BeanPostProcessor 的 postProcessBeforeInstantiation() 方法和 postProcessAfterInitialization() 方法。这两个方法主要是对代理对象进行检查以及初始化,并且进行创建其代理。
2.3 ProxyTransactionManagementConfiguration
再看下 ProxyTransactionManagementConfiguration 类:
/**
* 这是一个 @Configuration 类,它注册了 spring 基础类,这些类时启动基于代理的注解驱动的事务管理器的必要类。
*
* {@code @Configuration} class that registers the Spring infrastructure beans
* necessary to enable proxy-based annotation-driven transaction management.
*
* @author Chris Beams
* @author Sebastien Deleuze
* @since 3.1
* @see EnableTransactionManagement
* @see TransactionManagementConfigurationSelector
*/
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
/**
* 注册一个内部的事务增强器 org.springframework.transaction.config.internalTransactionAdvisor
*
* @param transactionAttributeSource
* @param transactionInterceptor
* @return
*/
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
// 设置事务属性源
advisor.setTransactionAttributeSource(transactionAttributeSource);
// 设置通知事务拦截器
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
/**
* 定义一个注解事务属性源
*
* @return
*/
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
// 注解的事务属性源
return new AnnotationTransactionAttributeSource();
}
/**
* 定义一个事务拦截器
*
* @param transactionAttributeSource
* @return
*/
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
// 设置事务属性源
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
// 设置事务管理器
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
这个类引入了三个 bean:AnnotationTransactionAttributeSource、TransactionInterceptor、BeanFactoryTransactionAttributeSourceAdvisor。
2.4 AnnotationTransactionAttributeSource
它是一个注解事务属性源,看下它的类图:
它的实现:
/**
* Implementation of the
* {@link org.springframework.transaction.interceptor.TransactionAttributeSource}
* interface for working with transaction metadata in JDK 1.5+ annotation format.
*
* <p>This class reads Spring's JDK 1.5+ {@link Transactional} annotation and
* exposes corresponding transaction attributes to Spring's transaction infrastructure.
* Also supports JTA 1.2's {@link javax.transaction.Transactional} and EJB3's
* {@link javax.ejb.TransactionAttribute} annotation (if present).
* This class may also serve as base class for a custom TransactionAttributeSource,
* or get customized through {@link TransactionAnnotationParser} strategies.
*
* @author Colin Sampaleanu
* @author Juergen Hoeller
* @since 1.2
* @see Transactional
* @see TransactionAnnotationParser
* @see SpringTransactionAnnotationParser
* @see Ejb3TransactionAnnotationParser
* @see org.springframework.transaction.interceptor.TransactionInterceptor#setTransactionAttributeSource
* @see org.springframework.transaction.interceptor.TransactionProxyFactoryBean#setTransactionAttributeSource
*/
@SuppressWarnings("serial")
public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
implements Serializable {
private static final boolean jta12Present;
private static final boolean ejb3Present;
static {
ClassLoader classLoader = AnnotationTransactionAttributeSource.class.getClassLoader();
jta12Present = ClassUtils.isPresent("javax.transaction.Transactional", classLoader);
ejb3Present = ClassUtils.isPresent("javax.ejb.TransactionAttribute", classLoader);
}
private final boolean publicMethodsOnly;
private final Set<TransactionAnnotationParser> annotationParsers;
/**
* Create a default AnnotationTransactionAttributeSource, supporting
* public methods that carry the {@code Transactional} annotation
* or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
*/
public AnnotationTransactionAttributeSource() {
this(true);
}
/**
* Create a custom AnnotationTransactionAttributeSource, supporting
* public methods that carry the {@code Transactional} annotation
* or the EJB3 {@link javax.ejb.TransactionAttribute} annotation.
* @param publicMethodsOnly whether to support public methods that carry
* the {@code Transactional} annotation only (typically for use
* with proxy-based AOP), or protected/private methods as well
* (typically used with AspectJ class weaving)
*/
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
this.publicMethodsOnly = publicMethodsOnly;
if (jta12Present || ejb3Present) {
this.annotationParsers = new LinkedHashSet<>(4);
this.annotationParsers.add(new SpringTransactionAnnotationParser());
if (jta12Present) {
this.annotationParsers.add(new JtaTransactionAnnotationParser());
}
if (ejb3Present) {
this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
}
}
else {
this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
}
}
/**
* Create a custom AnnotationTransactionAttributeSource.
* @param annotationParser the TransactionAnnotationParser to use
*/
public AnnotationTransactionAttributeSource(TransactionAnnotationParser annotationParser) {
this.publicMethodsOnly = true;
Assert.notNull(annotationParser, "TransactionAnnotationParser must not be null");
this.annotationParsers = Collections.singleton(annotationParser);
}
/**
* Create a custom AnnotationTransactionAttributeSource.
* @param annotationParsers the TransactionAnnotationParsers to use
*/
public AnnotationTransactionAttributeSource(TransactionAnnotationParser... annotationParsers) {
this.publicMethodsOnly = true;
Assert.notEmpty(annotationParsers, "At least one TransactionAnnotationParser needs to be specified");
this.annotationParsers = new LinkedHashSet<>(Arrays.asList(annotationParsers));
}
/**
* Create a custom AnnotationTransactionAttributeSource.
* @param annotationParsers the TransactionAnnotationParsers to use
*/
public AnnotationTransactionAttributeSource(Set<TransactionAnnotationParser> annotationParsers) {
this.publicMethodsOnly = true;
Assert.notEmpty(annotationParsers, "At least one TransactionAnnotationParser needs to be specified");
this.annotationParsers = annotationParsers;
}
@Override
public boolean isCandidateClass(Class<?> targetClass) {
for (TransactionAnnotationParser parser : this.annotationParsers) {
if (parser.isCandidateClass(targetClass)) {
return true;
}
}
return false;
}
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
// 从类上找事务属性
return determineTransactionAttribute(clazz);
}
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Method method) {
// 从方法上找事务属性
return determineTransactionAttribute(method);
}
/**
* Determine the transaction attribute for the given method or class.
* <p>This implementation delegates to configured
* {@link TransactionAnnotationParser TransactionAnnotationParsers}
* for parsing known annotations into Spring's metadata attribute class.
* Returns {@code null} if it's not transactional.
* <p>Can be overridden to support custom annotations that carry transaction metadata.
* @param element the annotated method or class
* @return the configured transaction attribute, or {@code null} if none was found
*/
@Nullable
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
// 遍历所有的注解解析器
for (TransactionAnnotationParser parser : this.annotationParsers) {
// 从事务注解解析器上解析
TransactionAttribute attr = parser.parseTransactionAnnotation(element);
if (attr != null) {
return attr;
}
}
return null;
}
/**
* By default, only public methods can be made transactional.
*/
@Override
protected boolean allowPublicMethodsOnly() {
return this.publicMethodsOnly;
}
@Override
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
}
if (!(other instanceof AnnotationTransactionAttributeSource)) {
return false;
}
AnnotationTransactionAttributeSource otherTas = (AnnotationTransactionAttributeSource) other;
return (this.annotationParsers.equals(otherTas.annotationParsers) &&
this.publicMethodsOnly == otherTas.publicMethodsOnly);
}
@Override
public int hashCode() {
return this.annotationParsers.hashCode();
}
}
这个类间接的实现了 TransactionAttributeSource 接口,间接的实现了它的 org.springframework.transaction.interceptor.TransactionAttributeSource#isCandidateClass 和 org.springframework.transaction.interceptor.TransactionAttributeSource#getTransactionAttribute 方法,这两个方法都是在 org.springframework.aop.support.AopUtils#canApply 这个方法中被调用的,AopUtils#canApply 方法又是在上面提到的实现了 BeanPostProcessor 接口的 postProcessAfterInitialization() 方法的 InfrastructureAdvisorAutoProxyCreator 类所实现。
2.4.1 判断是否候选类 isCandidateClass()
isCandidateClass() 方法:它在 bean 初始化之后,在获取通知和增强器的方法逻辑 getAdvicesAndAdvisorsForBean() 中调用 findAdvisorsThatCanApply(),再调用 canApply() 方法,根据 BeanFactoryTransactionAttributeSourceAdvisor 增强器,获取事务属性源切点 BeanFactoryTransactionAttributeSourceAdvisor#pointcut TransactionAttributeSourcePointcut 类型,获取切点 AnnotationTransactionAttributeSource 类,间接的调用它的 isCandidateClass() 方法,最后调用 SpringTransactionAnnotationParser 的 isCandidateClass() 方法,由 AnnotationUtils 工具类判断目标类是否有 @Transactional 来判断是否符合合格的类;
2.4.2 获取事务属性 TransactionAttribute 类型 getTransactionAttribute()
它实现 org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute:
/**
* 为这个方法执行获取事务属性。如果方法属性没有找到,默认是为类的事务属性。
*
* Determine the transaction attribute for this method invocation.
* <p>Defaults to the class's transaction attribute if no method attribute is found.
* @param method the method for the current invocation (never {@code null})
* @param targetClass the target class for this invocation (may be {@code null})
* @return a TransactionAttribute for this method, or {@code null} if the method
* is not transactional
*/
@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
// 首先,从缓存中找
// First, see if we have a cached value.
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// Value will either be canonical value indicating there is no transaction attribute,
// or an actual transaction attribute.
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
return cached;
}
}
else {
// 计算事务属性
// We need to work it out.
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// Put it in the cache.
if (txAttr == null) {
// 在缓存中标识事务属性为空
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
// 为事务属性设置方法描述符
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
DefaultTransactionAttribute dta = (DefaultTransactionAttribute) txAttr;
dta.setDescriptor(methodIdentification);
dta.resolveAttributeStrings(this.embeddedValueResolver);
}
if (logger.isTraceEnabled()) {
logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
// 加入到缓存
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
/**
* Determine a cache key for the given method and target class.
* <p>Must not produce same key for overloaded methods.
* Must produce same key for different instances of the same method.
* @param method the method (never {@code null})
* @param targetClass the target class (may be {@code null})
* @return the cache key (never {@code null})
*/
protected Object getCacheKey(Method method, @Nullable Class<?> targetClass) {
return new MethodClassKey(method, targetClass);
}
/**
* 计算属性源
*
* Same signature as {@link #getTransactionAttribute}, but doesn't cache the result.
* {@link #getTransactionAttribute} is effectively a caching decorator for this method.
* <p>As of 4.1.8, this method can be overridden.
* @since 4.1.8
* @see #getTransactionAttribute
*/
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// 不允许非 public 修饰的方法
// Don't allow no-public methods as required.
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
// 方法可能在接口上,但是我们需要从目标类上获取属性。
// 如果目标类是空,该方法将保持不变
// The method may be on an interface, but we need attributes from the target class.
// If the target class is null, the method will be unchanged.
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
// 首先尝试的是目标类上的方法
// First try is the method in the target class.
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
// 然后尝试的是在方法所在的类上
// Second try is the transaction attribute on the target class.
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
if (specificMethod != method) {
// 从方法上找
// Fallback is to look at the original method.
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// 最后在方法所在的接口上找
// Last fallback is the class of the original method.
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
return null;
}
getTransactionAttribute() 方法:也是在上述 isCandidateClass() 方法调用逻辑中的 org.springframework.aop.support.AopUtils#canApply 方法中,通过 TransactionAttributeSourcePointcut 类调用 matches() 方法,再调用 getTransactionAttributeSource() 方法获取事务属性源,最后获取事务属性 TransactionAttribute。它主要是在 org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute 这个方法中实现的逻辑:
- 先从缓存中查找事务属性;
- 计算事务属性 computeTransactionAttribute();
- 判断方法是否是 public 修饰的;
- 获取目标方法;
- 先从目标类上的方法查找 @Transcation 注解;
- 然后尝试从目标方法所在类上查找 @Transcation 注解;
- 在从接口的方法上查找 @Transcation 注解;
- 最后再从接口类上的查找 @Transcation 注解;
- 保存到缓存。
2.4.3 查找事务属性 findTransactionAttribute()
这个方法是一个重载方法,org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.Class<?>)
和 org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.reflect.Method)
,最终都调用到了 org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#determineTransactionAttribute 方法:
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
// 遍历所有的注解解析器
for (TransactionAnnotationParser parser : this.annotationParsers) {
// 从事务注解解析器上解析
TransactionAttribute attr = parser.parseTransactionAnnotation(element);
if (attr != null) {
return attr;
}
}
return null;
}
它通过事务注解解析器来解析:org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)
@Override
@Nullable
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
// 解析 @Transactional 注解
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
element, Transactional.class, false, false);
if (attributes != null) {
// 真正的开始解析
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
/**
* 开始解析事务注解
*
* @param attributes
* @return
*/
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
// 规则的事务属性
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());
String timeoutString = attributes.getString("timeoutString");
Assert.isTrue(!StringUtils.hasText(timeoutString) || rbta.getTimeout() < 0,
"Specify 'timeout' or 'timeoutString', not both");
rbta.setTimeoutString(timeoutString);
// 是否只读
rbta.setReadOnly(attributes.getBoolean("readOnly"));
// 事务名称
rbta.setQualifier(attributes.getString("value"));
rbta.setLabels(Arrays.asList(attributes.getStringArray("label")));
// 回滚规则
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;
}
可以看到它最终会返回一个 RuleBasedTransactionAttribute 类型的事务属性。
2.4.4 事务定义 RuleBasedTransactionAttribute
它的类图:
这个类实现了 TransactionDefinition 接口,我们看下这个接口类图是:
这个类主要定义了事务的一些基本属性信息,有事务名称、事务传播行为、事务隔离级别、超时时间、是否只读。
2.5 BeanFactoryTransactionAttributeSourceAdvisor
这个类的类图:
它的实现:
/**
* bean 工厂事务属性源增强器
*
* Advisor driven by a {@link TransactionAttributeSource}, used to include
* a transaction advice bean for methods that are transactional.
*
* @author Juergen Hoeller
* @since 2.5.5
* @see #setAdviceBeanName
* @see TransactionInterceptor
* @see TransactionAttributeSourceAdvisor
*/
@SuppressWarnings("serial")
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
@Nullable
private TransactionAttributeSource transactionAttributeSource;
/**
* 事务属性源切点
*/
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
// 获取事务属性源 AnnotationTransactionAttributeSource 类型
return transactionAttributeSource;
}
};
/**
* 通过注入
* Set the transaction attribute source which is used to find transaction
* attributes. This should usually be identical to the source reference
* set on the transaction interceptor itself.
* @see TransactionInterceptor#setTransactionAttributeSource
*/
public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
this.transactionAttributeSource = transactionAttributeSource;
}
/**
* Set the {@link ClassFilter} to use for this pointcut.
* Default is {@link ClassFilter#TRUE}.
*/
public void setClassFilter(ClassFilter classFilter) {
this.pointcut.setClassFilter(classFilter);
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
}
它是一个 PointcutAdvisor 类型实现类,切点增强器,它也是实现 getPointcut() 方法,返回一个 TransactionAttributeSourcePointcut 类,这个类在上面的 canApply() 方法中用到了。
2.6 TransactionInterceptor
这个类的类图:
再看下它的实现:
@SuppressWarnings("serial")
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
/**
* Create a new TransactionInterceptor.
* <p>Transaction manager and transaction attributes still need to be set.
* @see #setTransactionManager
* @see #setTransactionAttributes(java.util.Properties)
* @see #setTransactionAttributeSource(TransactionAttributeSource)
*/
public TransactionInterceptor() {
}
/**
* Create a new TransactionInterceptor.
* @param ptm the default transaction manager to perform the actual transaction management
* @param tas the attribute source to be used to find transaction attributes
* @since 5.2.5
* @see #setTransactionManager
* @see #setTransactionAttributeSource
*/
public TransactionInterceptor(TransactionManager ptm, TransactionAttributeSource tas) {
setTransactionManager(ptm);
setTransactionAttributeSource(tas);
}
/**
* Create a new TransactionInterceptor.
* @param ptm the default transaction manager to perform the actual transaction management
* @param tas the attribute source to be used to find transaction attributes
* @see #setTransactionManager
* @see #setTransactionAttributeSource
* @deprecated as of 5.2.5, in favor of
* {@link #TransactionInterceptor(TransactionManager, TransactionAttributeSource)}
*/
@Deprecated
public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
setTransactionManager(ptm);
setTransactionAttributeSource(tas);
}
/**
* Create a new TransactionInterceptor.
* @param ptm the default transaction manager to perform the actual transaction management
* @param attributes the transaction attributes in properties format
* @see #setTransactionManager
* @see #setTransactionAttributes(java.util.Properties)
* @deprecated as of 5.2.5, in favor of {@link #setTransactionAttributes(Properties)}
*/
@Deprecated
public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) {
setTransactionManager(ptm);
setTransactionAttributes(attributes);
}
/**
* 事务拦截器进行拦截调用
*
* @param invocation the method invocation joinpoint
* @return
* @throws Throwable
*/
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// 用事务去执行方法
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
//---------------------------------------------------------------------
// Serialization support
//---------------------------------------------------------------------
private void writeObject(ObjectOutputStream oos) throws IOException {
// Rely on default serialization, although this class itself doesn't carry state anyway...
oos.defaultWriteObject();
// Deserialize superclass fields.
oos.writeObject(getTransactionManagerBeanName());
oos.writeObject(getTransactionManager());
oos.writeObject(getTransactionAttributeSource());
oos.writeObject(getBeanFactory());
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
// Rely on default serialization, although this class itself doesn't carry state anyway...
ois.defaultReadObject();
// Serialize all relevant superclass fields.
// Superclass can't implement Serializable because it also serves as base class
// for AspectJ aspects (which are not allowed to implement Serializable)!
setTransactionManagerBeanName((String) ois.readObject());
setTransactionManager((PlatformTransactionManager) ois.readObject());
setTransactionAttributeSource((TransactionAttributeSource) ois.readObject());
setBeanFactory((BeanFactory) ois.readObject());
}
}
TransactionInterceptor 是一个实现了 MethodInterceptor 接口的 invoke() 方法,对方法执行进行拦截,间接调用了 org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction 方法:
/**
* 用于基于环绕通知子类的总代表,委派到该类的其他几个模板方法。能够处理 CallbackPreferringPlatformTransactionManager
* 和常规的 PlatformTransactionManager 实现类以及 ReactiveTransactionManager 实现类,对于无返回类型。
*
* General delegate for around-advice-based subclasses, delegating to several other template
* methods on this class. Able to handle {@link CallbackPreferringPlatformTransactionManager}
* as well as regular {@link PlatformTransactionManager} implementations and
* {@link ReactiveTransactionManager} implementations for reactive return types.
* @param method the Method being invoked
* @param targetClass the target class that we're invoking the method on
* @param invocation the callback to use for proceeding with the target invocation
* @return the return value of the method, if any
* @throws Throwable propagated from the target invocation
*/
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// 如果事务属性为空,那么这个方法就是非事务方法
// If the transaction attribute is null, the method is non-transactional.
// 获取事务属性源
TransactionAttributeSource tas = getTransactionAttributeSource();
// 获取事务属性
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 获取项目中事务管理器,一般是 DataSourceTransactionManager 类
final TransactionManager tm = determineTransactionManager(txAttr);
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
throw new TransactionUsageException(
"Unsupported annotated transaction on suspending function detected: " + method +
". Use TransactionalOperator.transactional extensions instead.");
}
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
if (adapter == null) {
throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
method.getReturnType());
}
return new ReactiveTransactionSupport(adapter);
});
return txSupport.invokeWithinTransaction(
method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);
}
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
// 获取我们需要切入的方法(也就是我们标识了 @Transactional 注解的方法)
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// 事务信息
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// 这是一个环绕通知:调用链中的下一个拦截器
// This is an around advice: Invoke the next interceptor in the chain.
// 这将会导致目标类被调用返回
// This will normally result in a target object being invoked.
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 抛出异常进行回滚
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 清理事务信息
cleanupTransactionInfo(txInfo);
}
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
// 提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
Object result;
final ThrowableHolder throwableHolder = new ThrowableHolder();
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
try {
Object retVal = invocation.proceedWithInvocation();
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
return retVal;
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
throwableHolder.throwable = ex;
return null;
}
}
finally {
cleanupTransactionInfo(txInfo);
}
});
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
catch (TransactionSystemException ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
ex2.initApplicationException(throwableHolder.throwable);
}
throw ex2;
}
catch (Throwable ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw ex2;
}
// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
}
梳理下这个方法的核心流程:
- 获取事务属性源 TransactionAttributeSource;
- 获取事务属性 TransactionAttribute,这里会返回 RuleBasedTransactionAttribute 类型;
- 获取事务管理器 TransactionManager;
- 获取方法描述器 joinpointIdentification;
- 执行 createTransactionIfNecessary() 方法,创建事务信息 TransactionInfo;
- 执行 invocation.proceedWithInvocation() 执行器方法,这将会执行调用链中下一个拦截器,如果没有拦截,则执行目标方法;
- 遇到异常之后执行 completeTransactionAfterThrowing() 方法,进行回滚或提交操作,然后抛出异常;
- 执行 cleanupTransactionInfo() 方法,清除事务信息;
- 没有异常的情况,执行 commitTransactionAfterReturning() 提交事务;
- 返回执行结果。
2.6.1 创建事务信息 createTransactionIfNecessary()
看下 org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary 这个创建事务信息方法:
/**
* 根据给定的事务属性来创建一个事务。
*
* Create a transaction if necessary based on the given TransactionAttribute.
* <p>Allows callers to perform custom TransactionAttribute lookups through
* the TransactionAttributeSource.
* @param txAttr the TransactionAttribute (may be {@code null})
* @param joinpointIdentification the fully qualified method name
* (used for monitoring and logging purposes)
* @return a TransactionInfo object, whether or not a transaction was created.
* The {@code hasTransaction()} method on TransactionInfo can be used to
* tell if there was a transaction created.
* @see #getTransactionAttributeSource()
*/
@SuppressWarnings("serial")
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// 包装事务属性,名称为方法描述符
// If no name specified, apply method identification as transaction name.
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
// 获取一个事务状态
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
// 获取事务,返回事务状态
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
// 准备事务信息
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
它的逻辑:
- 通过事务管理器获取事务状态 getTransaction();
- 准备事务信息 prepareTransactionInfo(),创建事务信息 TransactionInfo 类;
2.6.1.1 获取事务状态 getTransaction()
看下如何获取事务状态信息:org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction
/**
* 实现处理传播行为的方法,委派到 doGetTransaction、isExistingTransaction、doBegin 方法
*
* This implementation handles propagation behavior. Delegates to
* {@code doGetTransaction}, {@code isExistingTransaction}
* and {@code doBegin}.
* @see #doGetTransaction
* @see #isExistingTransaction
* @see #doBegin
*/
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// 获取事务定义
// Use defaults if no transaction definition given.
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
// 获取事务对象
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
// 判断是否存在事务
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
// 处理已存在的事务
return handleExistingTransaction(def, transaction, debugEnabled);
}
// 判断事务超时
// Check definition settings for new transaction.
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
// 判断事务传播行为 MANDATORY 必须的
// No existing transaction found -> check propagation behavior to find out how to proceed.
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// 挂起事务,但是当前没有事务
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
try {
// 开始一个新的事务
return startTransaction(def, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error ex) {
// 重新使用资源
resume(null, suspendedResources);
throw ex;
}
}
else {
// 创建一个空的事务,但是它会潜在的同步
// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + def);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
}
它的逻辑:
- 执行 doGetTransaction() 方法,获取事务对象,返回一个 DataSourceTransactionObject 类型对象;
- 判断是否存在事务 isExistingTransaction();
- 如果存在事务,执行 handleExistingTransaction() 方法,处理已存在的事务,结束;
- 判断事务是否超时,判断正确的传播行为;
- 判断传播行为如果是支持当前事务的(REQUIRED、REQUIRED_NEW、NESTED),先执行 suspend() 方法,挂起当前事务,然后执行 startTransaction() 开启一个新事物,结束;
- 否则执行 prepareTransactionStatus() 方法,创建一个空的事务,结束。
2.6.1.2 获取 DataSourceTransactionObject 事务对象 doGetTransaction()
看下它的实现 org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction:
/**
* 获取事务对象
*
* @return
*/
@Override
protected Object doGetTransaction() {
// 创建一个数据源事务对象
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
// 设置允许嵌套事务(保存点)
txObject.setSavepointAllowed(isNestedTransactionAllowed());
// 获取连接持有器
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
// 为数据源事务对象设置连接持有器(首次获取为空)
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
可以看到事务对象是一个 DataSourceTransactionObject 类型的对象,它的类图结构:
它拥有的属性有:连接持有器、是否允许保存点、是否只读、前一个事务隔离级别、是否新的连接持有器、是否仅支持回滚、是否必须还原自动提交属性等等。
上面的 doGetTransaction() 方法逻辑:
- 创建一个 DataSourceTransactionObject 类型对象;
- 设置是否允许保存点(即是否允许嵌套事务);
- 获取连接持有器(这里是从线程本地化中获取的,首次获取为 null);
- 为事务对象设置连接持有器。
2.6.1.3 判断是否存在事务 isExistingTransaction()
我们先看下它是如何判断事务是否存在的:org.springframework.jdbc.datasource.DataSourceTransactionManager#isExistingTransaction
/**
* 判断是否存在事务
*
* @param transaction the transaction object returned by doGetTransaction
* @return
*/
@Override
protected boolean isExistingTransaction(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
// 事务有连接持有器 && 连接持有器中的事务是活跃的
return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
}
- 事务对象是否有连接持有器;
- 连接持有器中的事务是否是活跃的。
2.6.1.4 处理已存在的事务 handleExistingTransaction()
接着看处理已经存在的事务 org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction 方法:
/**
* 为一个已经存在的事务,创建一个事务状态
*
* Create a TransactionStatus for an existing transaction.
*/
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// 判断传播行为:never 抛出异常
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
// 传播行为是 NOT_SUPPORTED 不执行事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
// 挂起当前事务
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
// 准备事务状态
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
// 传播行为:REQUIRES_NEW 开启一个新的事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
// 挂起当前事务
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
// 开启一个新的事务
return startTransaction(definition, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
// 传播行为:NESTED 嵌套事务
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
// 是否为嵌套事务保存点
if (useSavepointForNestedTransaction()) {
// Create savepoint within existing Spring-managed transaction,
// through the SavepointManager API implemented by TransactionStatus.
// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
// 创建一个新的事务状态
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
// 创建和持有保存点
status.createAndHoldSavepoint();
return status;
}
else {
// Nested transaction through nested begin and commit/rollback calls.
// Usually only for JTA: Spring synchronization might get activated here
// in case of a pre-existing JTA transaction.
// 开启事务
return startTransaction(definition, transaction, debugEnabled, null);
}
}
// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
// 验证现有的事务
if (isValidateExistingTransaction()) {
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
Constants isoConstants = DefaultTransactionDefinition.constants;
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] specifies isolation level which is incompatible with existing transaction: " +
(currentIsolationLevel != null ?
isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
"(unknown)"));
}
}
if (!definition.isReadOnly()) {
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] is not marked as read-only but existing transaction is");
}
}
}
// 传播行为:不是 NEVER,准备事务状态
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
逻辑:
- 判断传播行为,不同的传播行为执行不同的逻辑;
- 传播行为是 NOT_SUPPORTED 不执行事务;
- 先执行 suspend() 挂起当前事务;
- 执行 prepareTransactionStatus() 准备事务。
- 传播行为是 REQUIRES_NEW 开启新事物;
- 先执行 suspend() 挂起当前事务;
- 执行 startTransaction() 开启一个新事物。
- 传播行为是 NESTED 嵌套事务;
- 判断是否为嵌套事务使用保存点;
- 如果不是,则执行 startTransaction() 方法,开启一个新事物;
- 如果是,则先执行 prepareTransactionStatus() 创建一个新的事务状态 DefaultTransactionStatus,然后执行事务状态的 createAndHoldSavepoint() 创建保存点,返回。
- 验证现有的事务;
- 其他的传播行为,执行 prepareTransactionStatus() 方法,准备事务状态。
2.6.1.5 挂起事务 suspend()
挂起事务是 org.springframework.transaction.support.AbstractPlatformTransactionManager#suspend 方法中实现的:
/**
* 挂起给定的事务。首先挂起事务同步,然后委派 doSuspend 模板方法。
*
* Suspend the given transaction. Suspends transaction synchronization first,
* then delegates to the {@code doSuspend} template method.
* @param transaction the current transaction object
* (or {@code null} to just suspend active synchronizations, if any)
* @return an object that holds suspended resources
* (or {@code null} if neither transaction nor synchronization active)
* @see #doSuspend
* @see #resume
*/
@Nullable
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
// 判断是否同步是活跃的
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// 执行挂起同步
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {
Object suspendedResources = null;
if (transaction != null) {
// 对给定的事务进行挂起,返回一个当前连接资源
suspendedResources = doSuspend(transaction);
}
// 清除当前事务信息
// 当前事务名称
String name = TransactionSynchronizationManager.getCurrentTransactionName();
TransactionSynchronizationManager.setCurrentTransactionName(null);
// 是否只读
boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
// 隔离级别
Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
// 是哦福活跃
boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
TransactionSynchronizationManager.setActualTransactionActive(false);
// 创建新一个挂起资源持有器,把当前事务信息都保存起来
return new SuspendedResourcesHolder(
suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
}
catch (RuntimeException | Error ex) {
// doSuspend failed - original transaction is still active...
doResumeSynchronization(suspendedSynchronizations);
throw ex;
}
}
else if (transaction != null) {
// Transaction active but no synchronization active.
Object suspendedResources = doSuspend(transaction);
return new SuspendedResourcesHolder(suspendedResources);
}
else {
// Neither transaction nor synchronization active.
return null;
}
}
/**
* 挂起所有的当前同步,并且取消激活当前线程的事务同步
* Suspend all current synchronizations and deactivate transaction
* synchronization for the current thread.
* @return the List of suspended TransactionSynchronization objects
*/
private List<TransactionSynchronization> doSuspendSynchronization() {
// 获取当前线程中全部的事务同步
List<TransactionSynchronization> suspendedSynchronizations =
TransactionSynchronizationManager.getSynchronizations();
// 遍历同步,使其依次挂起
for (TransactionSynchronization synchronization : suspendedSynchronizations) {
// 就是释放数据库连接资源
synchronization.suspend();
}
// 清理同步
TransactionSynchronizationManager.clearSynchronization();
// 返回同步
return suspendedSynchronizations;
}
======================================= org.springframework.jdbc.datasource.DataSourceTransactionManager#doSuspend =======================================
/**
* 执行挂起事务
*
* @param transaction the transaction object returned by {@code doGetTransaction}
* @return
*/
@Override
protected Object doSuspend(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
txObject.setConnectionHolder(null);
// 释放资源
return TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
它的逻辑是:
- 执行挂起同步 doSuspendSynchronization() 方法,这里边主要是从线程本地化中获取所有的事务同步 TransactionSynchronization,然后执行挂起(就是释放数据库连接资源);
- 然后执行 doSuspend() 方法,挂起给定的事务,返回一个当前连接资源;
- 清除线程本地化中当前的事务信息,有线程名称、线程只读属性、线程隔离级别、事务是否活跃标识;
- 创建一个挂起的资源持有器 SuspendedResourcesHolder,返回。
- 遇到异常执行 doResumeSynchronization() 方法,重新使用同步。
2.6.1.6 准备事务状态 prepareTransactionStatus()
接着看准备事务状态方法 org.springframework.transaction.support.AbstractPlatformTransactionManager#prepareTransactionStatus :
/**
* 创建一个新的事务状态,同时初始化事务同步。
*
* Create a new TransactionStatus for the given arguments,
* also initializing transaction synchronization as appropriate.
* @see #newTransactionStatus
* @see #prepareTransactionStatus
*/
protected final DefaultTransactionStatus prepareTransactionStatus(
TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,
boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {
// 创建一个新的事务状态
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, newTransaction, newSynchronization, debug, suspendedResources);
// 预同步事务
prepareSynchronization(status, definition);
return status;
}
/**
* Create a TransactionStatus instance for the given arguments.
*/
protected DefaultTransactionStatus newTransactionStatus(
TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,
boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {
boolean actualNewSynchronization = newSynchronization &&
!TransactionSynchronizationManager.isSynchronizationActive();
// 创建一个默认的事务状态
return new DefaultTransactionStatus(
transaction, newTransaction, actualNewSynchronization,
definition.isReadOnly(), debug, suspendedResources);
}
/**
* Initialize transaction synchronization as appropriate.
*/
protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
// 判断是否为新的同步
if (status.isNewSynchronization()) {
// 设置实际事务活跃
TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
// 设置当前事务隔离级别
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ?
definition.getIsolationLevel() : null);
// 设置当前事务是否为只读
TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
// 设置当前事务的名称
TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
// 初始化同步
TransactionSynchronizationManager.initSynchronization();
}
}
逻辑:
- 执行 newTransactionStatus() 方法,创建一个事务状态 DefaultTransactionStatus 对象;
- 执行 prepareSynchronization() 方法,准备同步。
- 判断事务状态如果是新的同步,则执行以下逻辑;
- 设置线程本地化的实际事务活跃;
- 设置线程本地化的当前事务隔离级别;
- 设置线程本地化的当前事务是否为只读标识;
- 设置当前事务的名称;
- 初始化线程本地化同步集合。
2.6.1.7 事务状态 DefaultTransactionStatus
我们看下 DefaultTransactionStatus 对象的类图:
这个类有持有了一些事务的属性,表示当前事务的一个状态。
2.6.1.8 开启一个新事物 startTransaction()
开始看开启新事物方法 org.springframework.transaction.support.AbstractPlatformTransactionManager#startTransaction :
/**
* 开启一个新的事务
*
* Start a new transaction.
*/
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 创建一个事务状态
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 开启事务
doBegin(transaction, definition);
// 准备同步事务
prepareSynchronization(status, definition);
return status;
}
================================ org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin ================================
/**
* 开启一个新的事务
*
* @param transaction the transaction object returned by {@code doGetTransaction}
* @param definition a TransactionDefinition instance, describing propagation
* behavior, isolation level, read-only flag, timeout, and transaction name
*/
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
// 判断是否有连接持有器
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
// 获取一个新的连接
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
// 创建一个新的连接持有器,设置到事务对象中
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
// 设置连接持有器的事务同步属性
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
// 获取连接对象
con = txObject.getConnectionHolder().getConnection();
// 预设值连接属性,返回隔离级别
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
// 为事务对象设置隔离级别
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// 设置只读属性
txObject.setReadOnly(definition.isReadOnly());
// 获取自定提交的属性,设置为 false
// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already).
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
// 预处理事务连接
prepareTransactionalConnection(con, definition);
// 设置事务对象的连接持有器的活跃属性
txObject.getConnectionHolder().setTransactionActive(true);
// 超时时间
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// 绑定一个资源
// Bind the connection holder to the thread.
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
// 遇到异常,释放资源
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, obtainDataSource());
// 清空连接持有器
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
它的逻辑:
- 执行 newTransactionStatus() 方法,创建一个事务状态 DefaultTransactionStatus 对象;
- 执行 doBegin() 方法,开启事务;
- 判断事务对象 DataSourceTransactionObject 是否有连接持有器;
- 如果没有,创建一个新的连接 Connection、连接持有器 ConnectionHolder,并设置到事务对象中;
- 设置连接持有器的同步标识;
- 获取连接,为事务准备连接,
- 设置事务对象只读标识属性、隔离级别属性;
- 关闭连接的自动提交;
- 准备事务连接;
- 设置连接持有器的事务激活标识为 true;
- 设置事务对象的超时时间;
- 持有器是新的话,就绑定一个连接资源,到线程本地化中。
- 遇到异常,持有器是新的话,就释放资源,清空事务对象的连接持有器。
- 执行 prepareSynchronization() 方法,准备同步。
2.6.1.9 准备事务信息 prepareTransactionInfo()
获取了一个事务状态之后,接着到了准备事务信息方法了,org.springframework.transaction.interceptor.TransactionAspectSupport#prepareTransactionInfo:
/**
* 准备一个事务信息。
*
* Prepare a TransactionInfo for the given attribute and status object.
* @param txAttr the TransactionAttribute (may be {@code null})
* @param joinpointIdentification the fully qualified method name
* (used for monitoring and logging purposes)
* @param status the TransactionStatus for the current transaction
* @return the prepared TransactionInfo object
*/
protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, String joinpointIdentification,
@Nullable TransactionStatus status) {
// 创建一个事务信息
TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
if (txAttr != null) {
// We need a transaction for this method...
if (logger.isTraceEnabled()) {
logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
// 设置事务状态
// The transaction manager will flag an error if an incompatible tx already exists.
txInfo.newTransactionStatus(status);
}
else {
// The TransactionInfo.hasTransaction() method will return false. We created it only
// to preserve the integrity of the ThreadLocal stack maintained in this class.
if (logger.isTraceEnabled()) {
logger.trace("No need to create transaction for [" + joinpointIdentification +
"]: This method is not transactional.");
}
}
// We always bind the TransactionInfo to the thread, even if we didn't create
// a new transaction here. This guarantees that the TransactionInfo stack
// will be managed correctly even if no transaction was created by this aspect.
// 绑定线程
txInfo.bindToThread();
return txInfo;
}
逻辑:
- 创建一个事务信息 TransactionInfo 对象;
- 设置事务信息的事务状态属性;
- 把事务信息绑定到绑定线程,保存旧的事务信息,把当前事务信息绑定到线程本地化中;
- 返回事务信息。
我们看下这个 TransactionInfo 类信息:
它持有一个事务状态、事务管理器、事务属性、方法切点。
2.6.2 处理异常 completeTransactionAfterThrowing()
在执行器执行过程中遇到异常时,会执行 org.springframework.transaction.interceptor.TransactionAspectSupport#completeTransactionAfterThrowing 方法:
/**
* Handle a throwable, completing the transaction.
* We may commit or roll back, depending on the configuration.
* @param txInfo information about the current transaction
* @param ex throwable encountered
*/
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
"] after exception: " + ex);
}
// 判断是否对该异常进行回滚
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
// 进行回滚
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
}
else {
// 我们不会回滚这个异常。
// 如果 TransactionStatus.isRollbackOnly() 是 true,则任然回滚
// We don't roll back on this exception.
// Will still roll back if TransactionStatus.isRollbackOnly() is true.
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by commit exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by commit exception", ex);
throw ex2;
}
}
}
}
逻辑为:
- 判断是否对该异常进行回滚;
- 如果需要,则进行回滚;
- 如果不需要则执行提交事务。
2.6.3 清理事务信息 cleanupTransactionInfo()
当目标方法都处理完毕之后,不论有没有异常抛出,都进行清除事务信息 org.springframework.transaction.interceptor.TransactionAspectSupport#cleanupTransactionInfo:
/**
* Reset the TransactionInfo ThreadLocal.
* <p>Call this in all cases: exception or normal return!
* @param txInfo information about the current transaction (may be {@code null})
*/
protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
if (txInfo != null) {
// 恢复线程本地化状态
txInfo.restoreThreadLocalStatus();
}
}
private void restoreThreadLocalStatus() {
// Use stack to restore old transaction TransactionInfo.
// Will be null if none was set.
// 还原上一个事务信息
transactionInfoHolder.set(this.oldTransactionInfo);
}
主要是还原上一个事务信息到线程本地中。
2.6.4 提交事务 commitTransactionAfterReturning()
最后,当方法执行完毕,没有异常的情况下,会执行提交事务操作 org.springframework.transaction.interceptor.TransactionAspectSupport#commitTransactionAfterReturning:
/**
* Execute after successful completion of call, but not after an exception was handled.
* Do nothing if we didn't create a transaction.
* @param txInfo information about the current transaction
*/
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
// 提交事务
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
======================== org.springframework.transaction.support.AbstractPlatformTransactionManager#commit ====================
/**
* This implementation of commit handles participating in existing
* transactions and programmatic rollback requests.
* Delegates to {@code isRollbackOnly}, {@code doCommit}
* and {@code rollback}.
* @see org.springframework.transaction.TransactionStatus#isRollbackOnly()
* @see #doCommit
* @see #rollback
*/
@Override
public final void commit(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
// 事务状态是仅回滚的,执行回滚
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
processRollback(defStatus, false);
return;
}
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
processRollback(defStatus, true);
return;
}
// 执行提交
processCommit(defStatus);
}
/**
* 处理实际的回滚。已经检查了完成标记。
*
* Process an actual rollback.
* The completed flag has already been checked.
* @param status object representing the transaction
* @throws TransactionException in case of rollback failure
*/
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
boolean unexpectedRollback = unexpected;
try {
// 触发前置完成事件
triggerBeforeCompletion(status);
// 判断保存点
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
// 回滚到保存点
status.rollbackToHeldSavepoint();
}
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}
// 新的事务,进行回滚
doRollback(status);
}
else {
// Participating in larger transaction
// 判断是否有事务
if (status.hasTransaction()) {
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {
logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
}
// 设置仅回滚属性
doSetRollbackOnly(status);
}
else {
if (status.isDebug()) {
logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
}
}
}
else {
logger.debug("Should roll back transaction but cannot - no transaction available");
}
// Unexpected rollback only matters here if we're asked to fail early
if (!isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = false;
}
}
}
catch (RuntimeException | Error ex) {
// 触发完成之后事件
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw ex;
}
// 触发完成之后事件
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
// Raise UnexpectedRollbackException if we had a global rollback-only marker
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction rolled back because it has been marked as rollback-only");
}
}
finally {
// 完成之后的清理事件
cleanupAfterCompletion(status);
}
}
/**
* Process an actual commit.
* Rollback-only flags have already been checked and applied.
* @param status object representing the transaction
* @throws TransactionException in case of commit failure
*/
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
boolean unexpectedRollback = false;
prepareForCommit(status);
triggerBeforeCommit(status);
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Releasing transaction savepoint");
}
unexpectedRollback = status.isGlobalRollbackOnly();
// 释放保存点
status.releaseHeldSavepoint();
}
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
unexpectedRollback = status.isGlobalRollbackOnly();
// 执行提交
doCommit(status);
}
else if (isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = status.isGlobalRollbackOnly();
}
// Throw UnexpectedRollbackException if we have a global rollback-only
// marker but still didn't get a corresponding exception from commit.
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction silently rolled back because it has been marked as rollback-only");
}
}
catch (UnexpectedRollbackException ex) {
// can only be caused by doCommit
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
throw ex;
}
catch (TransactionException ex) {
// can only be caused by doCommit
if (isRollbackOnCommitFailure()) {
doRollbackOnCommitException(status, ex);
}
else {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
}
throw ex;
}
catch (RuntimeException | Error ex) {
if (!beforeCompletionInvoked) {
triggerBeforeCompletion(status);
}
doRollbackOnCommitException(status, ex);
throw ex;
}
// Trigger afterCommit callbacks, with an exception thrown there
// propagated to callers but the transaction still considered as committed.
try {
triggerAfterCommit(status);
}
finally {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
}
finally {
cleanupAfterCompletion(status);
}
}
这里的逻辑稍微复杂点:
- 判断事务状态是否是仅回滚的,如果是那就执行 processRollback() 方法,执行回滚;
- 执行 triggerBeforeCompletion() 方法,触发前置完成事件,底层调用事务同步 TransactionSynchronization 的 beforeCompletion() 方法;
- 判断一下条件,执行各自的逻辑
- 如果有保存点,那就执行事务状态的 rollbackToHeldSavepoint() 方法,回滚到保存点;
- 如果是新事物,执行 doRollback() 方法,进行回滚;
- 都不是,则执行 doSetRollbackOnly() 方法,给事务对象设置回滚标识,让上层事务进行回滚。
- 执行 triggerAfterCompletion() 方法,执行完成操作,底层调用事务同步 TransactionSynchronization 的 afterCompletion() 方法;
- 最后执行 cleanupAfterCompletion() 方法,进行清除操作。
- 新的同步则执行清理线程本地化操作;
- 新的事务,则执行释放连接操作;
- 如果有挂起的资源,恢复挂起的资源。
- 不是的话,就执行 processCommit() 方法,进行提交。
- 执行 triggerBeforeCommit() 方法,执行提交前的操作,底层调用事务同步 TransactionSynchronization 的 beforeCommit() 方法;
- 执行 triggerBeforeCompletion() 方法,执行完成前的操作,底层调用事务同步 TransactionSynchronization 的 beforeCompletion() 方法;
- 判断一下条件,执行各自的逻辑;
- 如果有保存点,则执行事务状态的 releaseHeldSavepoint() 方法,释放保存点;
- 如果是新的事务,则执行 doCommit() 方法,进行提交;
- 全局回滚时提前失败检查。
- 执行 triggerAfterCompletion() 方法,执行完成之后的操作,底层调用事务同步 TransactionSynchronization 的 afterCompletion() 方法;
- 遇到异常时,执行 doRollbackOnCommitException() 方法,进行回滚;
- 没有遇到异常,执行 triggerAfterCommit() 方法,执行完成之后的操作;
- 最后执行 cleanupAfterCompletion() 方法,进行清理操作。
- 新的同步则执行清理线程本地化操作;
- 新的事务,则执行释放连接操作;
- 如果有挂起的资源,恢复挂起的资源。
总结
上面就是 spring tx 模板的核心流程了。回顾下:
- 通过 @EnableTransactionManagement 注解,导入了 TransactionManagementConfigurationSelector 类;
- TransactionManagementConfigurationSelector 类,它导入了AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration 类;
- AutoProxyRegistrar 类负责注册一个 InfrastructureAdvisorAutoProxyCreator 类,它是一个创建代理对象的后置处理器;
- ProxyTransactionManagementConfiguration 类是创建了负责处理事务的增强器 BeanFactoryTransactionAttributeSourceAdvisor、还有处理事务属性的事务属性源 AnnotationTransactionAttributeSource、以及对目标方法进行事务处理拦截的事务拦截器 TransactionInterceptor,这三个 bean;
- 其中在调用目标方法时,通过事务拦截器 TransactionInterceptor 对目标方法进行拦截;
- 拦截有创建以及初始化事务相关信息(事务状态、事务对象、事务同步等信息)、执行目标方法、提交或者回滚事务、清理事务等流程。