spring中事务Transaction(@EnableTransactionManager @Transactional)实现机制源码解析

spring 事务部分共5篇文章

第一篇:spring中@EnableTransactionManager @Transactional注解实现机制

第二篇:spring boot中事务功能自动配置的加载过程分析

第三篇:spring@Transactional注解属性字段含义

第四篇:spring @Transactional如何测试事务注解生效

第五篇:spring及spring boot中事务相关知识的总结

本篇为第一篇

先提出几个问题

1. 为什么在spring中加入了@EnableTransactionManagement就会开启事务支持呢?

2. @EnableTransactionManagement与@Transactional是如何配合以实现事务效果的呢?

3. spring中的方法与mysql中真正的事务执行语句是如何对应起来的?

4. @Transactional注解的处理,以及拦截器将代理织入,事务执行的时候通过代理对象来执行,这块的源码是怎样的

1. @EnableTransactionManagement作用

@Import(TransactionManagementConfigurationSelector.class)

public @interface EnableTransactionManagement {

 

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

    @Override
    protected String[] selectImports(AdviceMode adviceMode) {
        switch (adviceMode) {
            case PROXY:
                return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
            case ASPECTJ:
                return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
            default:
                return null;
        }
    }
}

默认adviceMode是PROXY

利用TransactionManagementConfigurationSelector给容器中会导入组件

导入两个组件AutoProxyRegistrar及ProxyTransactionManagementConfiguration

2. AutoProxyRegistrar的作用--注册InfrastructureAdvisorAutoProxyCreator 组件

给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件;

org.springframework.context.annotation.AutoProxyRegistrar#registerBeanDefinitions

AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);

InfrastructureAdvisorAutoProxyCreator

类图

其与spring aop中的AnnotationAwareAutoProxyCreator的BeanPostProcessor非常类似

原理也是:利用InfrastructureAdvisorAutoProxyCreator后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器)

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
    Object cacheKey = getCacheKey(beanClass, beanName);
    
    // Create proxy here if we have a custom TargetSource.
    // Suppresses unnecessary default instantiation of the target bean:
    // The TargetSource will handle target instances in a custom fashion.
    if (beanName != null) {
        TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
        if (targetSource != null) {
            this.targetSourcedBeans.add(beanName);
            Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
            Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
            this.proxyTypes.put(cacheKey, proxy.getClass());
            return proxy;
        }
    }

    return null;
}

如我们在EmployeeService中的saveTwoEmployee方法上添加了@Transactional注解

这里我们就可以看到,容器中employeeService这个bean在初始化阶段就已经被InfrastructureAdvisorAutoProxyCreator这个BeanPostProcessor包装为代理对象了,以后从容器中取出的这个singleton bean都是代理对象

查看CGLIB$CALLBACK_0

可以看到其织入了三个切面,前两个是DruidStatInterceptor,最后一个是TransactionInterceptor

如果想了解BeanPostProcessor是如何包装对象使其成为代理对象的,参考:

spring aop源码解析1: 创建、初始化并注册AnnotationAwareAspectJAutoProxyCreator

3. ProxyTransactionManagementConfiguration作用

其是一个@Configuration配置类,来给容器中注册@Bean组件

@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {}

注册事务增强器

在ProxyTransactionManagementConfiguration中,注册了transactionAdvisor bean

@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
    
    BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
    
    advisor.setTransactionAttributeSource(transactionAttributeSource());
    // 为Advisor添加Advice,Advice就是transactionInterceptor
    advisor.setAdvice(transactionInterceptor());
    advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
    return advisor;
}

事务属性类也是一个@Bean

@Bean

@Role(BeanDefinition.ROLE_INFRASTRUCTURE)

public TransactionAttributeSource transactionAttributeSource() {

   return new AnnotationTransactionAttributeSource();

}

org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#AnnotationTransactionAttributeSource(boolean)

public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
    this.publicMethodsOnly = publicMethodsOnly;
    this.annotationParsers = new LinkedHashSet<TransactionAnnotationParser>(2);
    this.annotationParsers.add(new SpringTransactionAnnotationParser());
}

在这里创建一个自定义的AnnotationTransactionAttributeSource,支持带有@Transactional注释的public方法

org.springframework.transaction.annotation.SpringTransactionAnnotationParser

在SpringTransactionAnnotationParser#parseTransactionAnnotation方法中处理@Transactional注解

AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);

解析@Transactional中的每一个信息,封装到AnnotationAttributes对象中

事务增强器要用事务注解的信息,AnnotationTransactionAttributeSource解析@Transactional注解

注册事务拦截器

org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration

注册了transactionInterceptor bean

@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
    TransactionInterceptor interceptor = new TransactionInterceptor();
    interceptor.setTransactionAttributeSource(transactionAttributeSource());
    if (this.txManager != null) {
        interceptor.setTransactionManager(this.txManager);
    }
    return interceptor;
}

TransactionInterceptor;保存了事务属性信息,事务管理器;

其是一个 MethodInterceptor;

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
    
}

invoke方法调用

org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

来处理commit及rollback

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
			throws Throwable {

		// If the transaction attribute is null, the method is non-transactional.
		final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
			// Standard transaction demarcation 划界 with getTransaction and commit/rollback calls.
			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
			Object retVal = null;
			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);
			}
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

		else {
			// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
			try {
				Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
						new TransactionCallback<Object>() {
							@Override
							public Object doInTransaction(TransactionStatus status) {
								TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
								try {
									return invocation.proceedWithInvocation();
								}
								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.
										return new ThrowableHolder(ex);
									}
								}
								finally {
									cleanupTransactionInfo(txInfo);
								}
							}
						});

				// Check result: It might indicate a Throwable to rethrow.
				if (result instanceof ThrowableHolder) {
					throw ((ThrowableHolder) result).getThrowable();
				}
				else {
					return result;
				}
			}
			catch (ThrowableHolderException ex) {
				throw ex.getCause();
			}
		}
	}

4. 执行目标方法(执行拦截器链)

目标方法执行的时候,执行拦截器链;

先看一下整体的流程图

spring事务中拦截器触发过程流程图:

构造拦截器链

容器中保存了组件如employeeService的代理对象(cglib增强后的对象),这个对象里面保存了详细信息(比如增强器,目标对象等)

CglibAopProxy.intercept();拦截目标方法的执行

org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor

其拦截器链(项目中使用了druid连接池)

获取事务相关的属性

final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);

获取PlatformTransactionManager

final PlatformTransactionManager tm = determineTransactionManager(txAttr);

 

org.springframework.transaction.interceptor.TransactionAspectSupport#determineTransactionManager

protected PlatformTransactionManager determineTransactionManager(TransactionAttribute txAttr) {
    // Do not attempt to lookup tx manager if no tx attributes are set
    if (txAttr == null || this.beanFactory == null) {
        return getTransactionManager();
    }
    String qualifier = txAttr.getQualifier();
    
    // 如果我们在@Transactional中指定TransactionalManager(qualifier)
    if (StringUtils.hasText(qualifier)) {
        return determineQualifiedTransactionManager(qualifier);
    }
    else if (StringUtils.hasText(this.transactionManagerBeanName)) {
        return determineQualifiedTransactionManager(this.transactionManagerBeanName);
    }
    // 如果没有指定,那么最终会从容器中按照类型获取一个PlatformTransactionManager;
    // 如果是jdbc,那么就使用DataSourceTransactionManager
    else {
        PlatformTransactionManager defaultTransactionManager = getTransactionManager();
        
        if (defaultTransactionManager == null) {
            defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
            
            if (defaultTransactionManager == null) {
                defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);
                this.transactionManagerCache.putIfAbsent(
                    DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
            }
            
        }
        return defaultTransactionManager;
    }
}

如果我们在@Transactional中指定TransactionalManager(qualifier)

如果没有指定,那么最终会从容器中按照类型获取一个PlatformTransactionManager;

如果是jdbc,那么就使用DataSourceTransactionManager

如果是jpa,那么就使用JpaTransactionManager

获取到的transactionManager

获取切点

final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

执行织入的增强方法和目标方法

代理对象执行目标方法时执行拦截器链

前两个druidStatInterceptor就不关心了

直接看TransactionalInterceptor的invoke方法

TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

先将connection的autoCommit设置为false

begin transaction;

之后设置@Transactional注解的属性,如isolation,rollback等

 

之后开始执行真正的目标方法,执行多条sql语句

retVal = invocation.proceedWithInvocation();
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);
}
commitTransactionAfterReturning(txInfo);
return retVal;

如果异常,那么通过调用completeTransactionAfterThrowing

获取到事务管理器,利用事务管理回滚操作;

 

如果正常,调用commitTransactionAfterReturning

利用事务管理器,提交事务

5. 通过console查看事务实际执行过程

为了查看事务执行的过程,要在applicationContext.properties中开启

logging.level.org.springframework.transaction=trace

1. 识别到@Transactional注解

调用二次

一次是SimpleJpaRepository类上的注解

另一次是save方法上的注解(覆盖了类上的注解)

2. addEmp

3. saveEmpLog

4. 方法结束时再调用一次

注意:

如果执行的是update tbl_employee操作,不是前面的insert tbl_employee操作,其sql的执行过程是这样的

前两步还是一样的

第三步只有一条select语句

第四步相同

第五步来执行update tbl_employee

源码参考:https://gitee.com/constfafa/spring-data-jpa-demo.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值