本文内容
-
@Transactional事务使用
-
@EnableTransactionManagement 详解
-
@Transactional事务属性的解析
-
TransactionInterceptor 事务控制
声明式事务使用和原理
声明式的主要步骤
- 使用@EnableTransactionManagement启用Spring 事务管理支持
- 使用@Transactional标识需要事务的方法会自动开启事务
- 注入数据源和事务管理器
下面通过案例演示一下上面的效果。
案例
-
使用@EnableTransactionManagement启用Spring 事务管理支持,配置类上需要有@Configuration注解
@Configuration @ComponentScan @EnableTransactionManagement public class AppConfig {}
-
使用@Transactional标识需要事务的方法会自动开启事务。
addUser
方法需要事务@Service public class UserService { @Autowired private JdbcTemplate jdbcTemplate; @Transactional public void addUser() { System.out.println("执行前记录:" + jdbcTemplate.queryForList("SELECT * from t_user")); jdbcTemplate.update("insert into t_user (name) values (?)", "xx"); jdbcTemplate.update("insert into t_user (name) values (?)", "oo"); System.out.println("执行后记录:" + jdbcTemplate.queryForList("SELECT * from t_user")); } }
-
注入数据源和事务管理器
@Configuration @ComponentScan @EnableTransactionManagement public class AppConfig { /** * 定义一个数据源 * @return */ @Bean public DataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(""); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://192.168.25.24:3306/xxx?characterEncoding=UTF-8"); dataSource.setUsername("root"); dataSource.setPassword("xxx"); return dataSource; } /** * 定义一个JdbcTemplate来执行sql * @param dataSource * @return */ @Bean public JdbcTemplate jdbcTemplate(DataSource dataSource) { return new JdbcTemplate(dataSource); } /** * 定义一个管理器 * @param dataSource * @return */ @Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }
-
测试程序
public class DeclarativeTest { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); UserService userService = context.getBean(UserService.class); userService.addUser(); context.close(); } }
输出结果如下:
执行前记录:[{id=1, name=test1-1}, {id=2, name=test1-2}, {id=3, name=xx}, {id=4, name=oo}, {id=5, name=xx}, {id=6, name=oo}] 执行后记录:[{id=1, name=test1-1}, {id=2, name=test1-2}, {id=3, name=xx}, {id=4, name=oo}, {id=5, name=xx}, {id=6, name=oo}, {id=7, name=xx}, {id=8, name=oo}]
原理
@EnableTransactionManagement注解会开启Spring自动管理事务的功能。开启之后在Spring容器启动的过程中,会拦截所有bean的创建过程,判断bean 是否需要让Spring来管理事务,如果需要那么通过aop的方式创建代理对象。代理中会添加一个拦截器TransactionInterceptor
,拦截@Trasaction
标识方法的执行,在方法执行前后添加事务的功能。
下面进行源码分析,需要用到的前置只是是Spring Aop相关知识和编程式事务管理的知识,前面的文章有涉及,提前看一下。
@EnableTransactionManagement 详解
@EnableTransactionManagement 会开启Spring的事务管理功能,查看下源码。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
/**
* 指示是否创建基于子类(CGLIB)的代理(true),而不是标准的基于Java接口的代理(false)。默认为false。
* 仅当mode()设置为AdviceMode.PROXY时适用。
*/
boolean proxyTargetClass() default false;
/**
* 指示应该如何应用事务通知。 默认值是AdviceMode.PROXY。
* 请注意,代理模式只允许通过代理拦截调用。同一类内的本地调用不会被拦截;
* 在本地调用中,对这种方法的Transactional注释将被忽略,因为Spring的拦截器甚至不会在这样的运行时场景中起作用。
*/
AdviceMode mode() default AdviceMode.PROXY;
/**
* 当在特定连接点上应用多个通知时,指示事务顾问程序的执行顺序。 默认值是Ordered.LOWEST_PRECEDENCE
*/
int order() default Ordered.LOWEST_PRECEDENCE;
}
3个参数属性值
- proxyTargetClass : 指示是否创建基于子类(CGLIB)的代理(true),而不是标准的基于Java接口的代理(false)
- mode:指示应该如何应用事务通知。 默认值是AdviceMode.PROXY。
- order: 当在特定连接点上应用多个通知时,指示事务顾问程序的执行顺序。 默认值是Ordered.LOWEST_PRECEDENCE,最后处理事务拦截器。
TransactionManagementConfigurationSelector
重点是@Import(TransactionManagementConfigurationSelector.class)
,注入一些事务相关的bean到Spring容器中进行事务的管理控制。
根据EnableTransactionManagement的mode值选择应该使用AbstractTransactionManagementConfiguration的哪个实现。
package org.springframework.transaction.annotation;
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector {
/**
* 此处是AdviceMode的作用,默认是用代理,另外一个是ASPECTJ
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
// @1
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);
}
}
我们的mode是 AdviceMode.PROXY ,所以走@1位置,注入AutoProxyRegistrar
和 ProxyTransactionManagementConfiguration
。
AutoProxyRegistrar注入 InfrastructureAdvisorAutoProxyCreator
AutoProxyRegistrar
的作用是注入一个InfrastructureAdvisorAutoProxyCreator
,用于拦截bean的创建过程,为需要的事务控制的bean 创建代理对象,这个类非常关键,后面详细讲。
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
Set annTypes = importingClassMetadata.getAnnotationTypes();
// 遍历所有注解,找到有mode和proxyTargetClass的注解
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) {
// 注册aop InfrastructureAdvisorAutoProxyCreator 不展开
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
// 强制设置proxyTargetClass=true后面使用cglib
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
}
}
ProxyTransactionManagementConfiguration
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@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.getNumber("order"));
}
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@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;
}
}
ProxyTransactionManagementConfiguration
代理事务配置,注册事务需要用的一些类,而且Role=ROLE_INFRASTRUCTURE都是属于内部级别的,如下:
BeanFactoryTransactionAttributeSourceAdvisor
事务属性通知器,存放事务注解的方法相关的属性TransactionAttributeSource
事务属性源,就是事务注解的一些属性,也用来解析事务注解属性,实际是AnnotationTransactionAttributeSource
TransactionInterceptor
事务拦截器,该类包含与Spring底层事务API的集成。TransactionInterceptor
简单地以正确的顺序调用相关的超类方法,比如invokeWithinTransaction
。这个类非常关键,负责事务相关的AOP增强的。
小结
EnableTransactionManagement注解的作用主要注入了InfrastructureAdvisorAutoProxyCreator
负责拦截bean的创建过程为特定的bean创建代理对象,并通过TransactionInterceptor
事务拦截器来实现方法的事务控制。
@Transactional 详解
该注解用于描述单个方法或类上的事务属性。在类级别,该注释作为默认值应用于声明类及其子类的所有方法。注意,类级别它并不适用于类层次结构上的父类,也就是父类方法需要在本地重新声明,以便参与子类级别的注释。
注解的属性的语义的具体信息,由 TransactionDefinition
和 TransactionAttribute
提供。
package org.springframework.transaction.annotation;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";
/**
* 用来确定目标事务管理器bean
*/
@AliasFor("value")
String transactionManager() default "";
/**
* 事务传播类型
*/
Propagation propagation() default Propagation.REQUIRED;
/**
* 事务隔离级别
*/
Isolation isolation() default Isolation.DEFAULT;
/**
* 事务超时
*/
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
/**
* 只读事务
*/
boolean readOnly() default false;
/**
* 指定哪些异常类型必须导致事务回滚,指定Throwable的子类型;默认只回滚RuntimeException和Error
*/
Class extends Throwable>[] rollbackFor() default {};
/**
* 指示哪些异常类型必须导致事务回滚,这里异常类名称
*/
String[] rollbackForClassName() default {};
/**
* 指定哪些异常不进行回滚
*/
Class extends Throwable>[] noRollbackFor() default {};
/**
* 指定哪些异常类型不进行回滚,异常类型名称
*/
String[] noRollbackForClassName() default {};
}
@Transactional注解如何解析成事务属性
AnnotationTransactionAttributeSource类
从类图看我们关注AnnotationTransactionAttributeSource
通过SpringTransactionAnnotationParser
将@Transcation
转成事务属性供Spring事务处理使用。
- 如果
@Transcation
注解配置了属性,转换成RuleBasedTransactionAttribute
- 如果
@Transcation
注解没有配置属性,转换成DefaultTransactionAttribute
,只有在抛出RuntimeException
和Error
时候才回滚
按照Spring源码设计设计的一般套路我们看下右侧的TransactionAttributeSource
接口和抽象类AbstractFallbackTransactionAttributeSource
TransactionAttributeSource 接口
public interface TransactionAttributeSource {
/**确定给定的类是否是TransactionAttributeSource元数据格式的事务属性的候选类*/
default boolean isCandidateClass(Class> targetClass) {
return true;
}
/**解析给定方法的@Transaction事务属性,如果方法是非事务性的,则返回null*/
@Nullable
TransactionAttribute getTransactionAttribute(Method method, @Nullable Class> targetClass);
}
AbstractFallbackTransactionAttributeSource类
先看getTransactionAttribute()
方法
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class> targetClass) {
// 判断method所在的class是不是Object类型
if (method.getDeclaringClass() == Object.class) {
return null;
}
// First, see if we have a cached value.
// 构建缓存key
Object cacheKey = getCacheKey(method, targetClass);
// 从缓存中获取 @1
TransactionAttribute cached = this.attributeCache.get(cacheKey);
// 有缓存,不会每次computeTransactionAttribute
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) txAttr).setDescriptor(methodIdentification);
}
if (logger.isTraceEnabled()) {
logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
// 加入缓存
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
缓存中有类对应方法的事务属性就直接返回,没有就先解析@1再缓存起来。
computeTransactionAttribute
方法
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class> targetClass) {
// Don't allow no-public methods as required.
// 首先判断方法是否是public,默认是支持public的
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代表实现类中的方法
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;
}
查找事务属性的查找顺序如下:
- 特定的目标方法,会去找父类或者接口的方法
- 目标类,会去找父类或者接口
- 声明的方法
- 声明方法所在的类
AnnotationTransactionAttributeSource#determineTransactionAttribute()
方法委托给SpringTransactionAnnotationParser
解析给定类或是方法上的@Transactional
注解的事务属性
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
// 获取我们的注解解析器
for (TransactionAnnotationParser parser : this.annotationParsers) {
// 通过注解解析器去解析我们的元素(方法或者类)上的注解
TransactionAttribute attr = parser.parseTransactionAnnotation(element);
if (attr != null) {
return attr;
}
}
return null;
}
接下来看下是如何解析和包装的SpringTransactionAnnotationParser#parseTransactionAnnotation()
方法。
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
// 从element对象中获取@Transactional注解,然后把注解属性封装到了AnnotationAttributes
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
element, Transactional.class, false, false);
if (attributes != null) {
// 解析出真正的事务属性对象
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
分析2个点:
AnnotatedElementUtils.findMergedAnnotationAttributes()
负责解析目标类或目标方法上的@Transactional
,会向上找父类或是接口的parseTransactionAnnotation()
方法包装成TransactionAttribute
看下是如何包装转换的。
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
// 创建一个基础规则的事务属性对象
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
// 解析@Transactionl上的传播行为
Propagation propagation = attributes.getEnum("propagation");
rbta.setPropagationBehavior(propagation.value());
// 解析@Transactionl上的隔离级别
Isolation isolation = attributes.getEnum("isolation");
rbta.setIsolationLevel(isolation.value());
// 解析@Transactionl上的事务超时事件
rbta.setTimeout(attributes.getNumber("timeout").intValue());
// 解析readOnly
rbta.setReadOnly(attributes.getBoolean("readOnly"));
// 解析@Transactionl上的事务管理器的名称
rbta.setQualifier(attributes.getString("value"));
List 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;
}
至此,@Transactional
是如何变成RuleBasedTransactionAttribute
已经很清晰了。
如何自动生成代理对象
这部分和之前的声明式AOP的源码分析是一样的过程,通过类图过一下。
-
谁负责创建代理?
InfrastructureAdvisorAutoProxyCreator
继承我们熟悉的AbstractAdvisorAutoProxyCreator
类,是个BeanPostProcessor
,在Spring容器启动的过程中,会拦截bean的创建过程,为需要事务支持的bean生成代理对象。 -
谁负责判断bean是否需要代理?
BeanFactoryTransactionAttributeSourceAdvisor
是个Advisor,组合了切点和通知。哪些bean需要代理满足增强由切点TransactionAttributeSourcePointcut
来通过TransactionAttributeSource
来判定bean的类或是方法上是否有@Transactional
注解。 -
谁负责实际的事务增强工作?
TransactionInterceptor 继承
MethodInterceptor
是个拦截器,负责拦截代理对象目标方法,在前后增加事务控制的逻辑。这个类下面进行详细分析。
TransactionInterceptor 如何进行事务控制
TransactionInterceptor类
Spring中声明式事务时通过AOP的方式实现的,事务方法的执行最终都会由TransactionInterceptor
的invoke()
拦截增强的。
package org.springframework.transaction.interceptor;
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
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属性
Class> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
/**
* 以事务的方式调用目标方法
* 在这埋了一个钩子函数 用来回调目标方法的
*/
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
事务的实现是委托给TransactionAspectSupport
父类实现的。
TransactionAspectSupport类
invokeWithinTransaction() 方法
基于环绕通知的实现事务控制,委托给该类上的其他几个模板方法,其实里面主要内容就是编程式的事务控制了。这是个模板方法,主要功能点如下:
- 如何获取事务管理器对象
- 通过事务管理器开启事务
- 执行目标方法
- 方法异常如何完成事务
- 正常返回如何完成事务提交
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class> targetClass,
final InvocationCallback invocation) throws Throwable {
// 获取我们的事务属性源对象
TransactionAttributeSource tas = getTransactionAttributeSource();
// 通过事务属性源对象获取到当前方法的事务属性信息
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// @1获取我们配置的事务管理器对象
final TransactionManager tm = determineTransactionManager(txAttr);
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
// 获取连接点的唯一标识 类名+方法名
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
// 声明式事务处理
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// @2创建TransactionInfo
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// 执行被增强方法,调用具体的处理逻辑
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
//@3 异常回滚 如何走?可能只需提交,也可能只需回滚,这个取决于事务的配置
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
//清除事务信息,恢复线程私有的老的事务信息
cleanupTransactionInfo(txInfo);
}
//成功后提交,会进行资源储量,连接释放,恢复挂起事务等操作
commitTransactionAfterReturning(txInfo);
return retVal;
}
}
determineTransactionManager() 事务管理器获取
查找和获取的顺序是:
- 先看@Transactional中是否通过value或者transactionManager指定了事务管理器
- TransactionInterceptor.transactionManagerBeanName是否有值,如果有,将通过这个值查找事务管理器
- TransactionInterceptor.transactionManager是否有值,如果有则返回,这个是通过容器TransactionManagementConfigurer接口设置到TransactionInterceptor中的
- 如果上面3种都没有,将从Spring容器中查找TransactionManager类型的作为默认事务管理器
protected TransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
// Do not attempt to lookup tx manager if no tx attributes are set
// txAttr == null || this.beanFactory == null ,返回拦截器中配置的事务管理器
if (txAttr == null || this.beanFactory == null) {
return getTransactionManager();
}
//qualifier就是@Transactional注解中通过value或者transactionManager来指定事务管理器的bean名称
String qualifier = txAttr.getQualifier();
if (StringUtils.hasText(qualifier)) {
//从spring容器中查找[beanName:qualifier,type:TransactionManager]的bean
return determineQualifiedTransactionManager(this.beanFactory, qualifier);
}
else if (StringUtils.hasText(this.transactionManagerBeanName)) {
//从spring容器中查找[beanName:this.transactionManagerBeanName,type:TransactionManager]的bean
return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
}
else {
//最后通过类型TransactionManager在spring容器中找事务管理器
TransactionManager defaultTransactionManager = getTransactionManager();
if (defaultTransactionManager == null) {
defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
if (defaultTransactionManager == null) {
defaultTransactionManager = this.beanFactory.getBean(TransactionManager.class);
this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
}
return defaultTransactionManager;
}
}
createTransactionIfNecessary() 创建并开启事务
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// 如果没有名称指定则使用方法唯一标识,并使用DelegatingTransactionAttribute封装txAttr
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) {
// @1获取TransactionStatus事务状态信息
status = tm.getTransaction(txAttr);
}
}
// @2根据指定的属性与status准备一个TransactionInfo,
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
分析如下:
- @1获取TransactionStatus事务状态信息,也就是是编程式事务的创建和开启。
- @2TransactionInfo生成
prepareTransactionInfo()
方法创建事务信息并绑定到当前线程
protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, String joinpointIdentification,
@Nullable TransactionStatus status) {
// 创建事务信息
TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
if (txAttr != null) {
// The transaction manager will flag an error if an incompatible tx already exists.
// 设置新事务状态
txInfo.newTransactionStatus(status);
}
// 事务信息绑定到当前线程
txInfo.bindToThread();
return txInfo;
}
事务信息是有哪些内容?简单过一下内部类TransactionInfo
/**
* 用于保存事务信息的不透明对象。子类必须将其传递回该类的方法,但不能看到其内部
*/
protected static final class TransactionInfo {
/** 事务管理器 */
@Nullable
private final PlatformTransactionManager transactionManager;
/** 事务属性 */
@Nullable
private final TransactionAttribute transactionAttribute;
/** 切点标识名 */
private final String joinpointIdentification;
/** 事务状态 */
@Nullable
private TransactionStatus transactionStatus;
/** 旧的事务信息 */
@Nullable
private TransactionInfo oldTransactionInfo;
/**
* 绑定新事务到当前线程,旧的会被保存
*/
private void bindToThread() {
this.oldTransactionInfo = transactionInfoHolder.get();
transactionInfoHolder.set(this);
}
/**
* 恢复线程中旧事务信息
*/
private void restoreThreadLocalStatus() {
transactionInfoHolder.set(this.oldTransactionInfo);
}
}
completeTransactionAfterThrowing() 异常后完成事务
/**
* 如果支持回滚的话就进行回滚,否则就处理提交,提交里面如果TransactionStatus.isRollbackOnly()=true的话也会进行回滚处理
*/
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);
}
// @1判断事务是否需要回滚
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
// 进行回滚
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
}
else {
// We don't roll back on this exception.
// Will still roll back if TransactionStatus.isRollbackOnly() is true.
try {
// @2通过事务管理器提交事务
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
}
}
异常后如果匹配上我们@Transaction
指定的异常类型,在调用事务管理器进行事务回滚,否则通过事务管理器进行提交事务。
commitTransactionAfterReturning 正常完成事务
通过事务管理器进行事务提交。
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
小结
TransactionInterceptor 对事务控制包括开启、提交、回滚等操作,其实都是通过事务管理器进行的,这和编程式事务管理是一样的。
总结
本文进行了Spring中@Transactional声明事务的源码解析,结合了声明式AOP的源码分析和编程式事务管理的源码分析。总结下过程是就是通过BeanPostProcessor拦截bean创建过程自动创建代理对象,通过TransactionInterceptor 环绕通知增强目标方法,在目标方法执行前后增加事务的控制逻辑。
知识分享,转载请注明出处。学无先后,达者为先!