一、spring事务使用流程
1、使用spring提供的事务管理的时候,需要向容器中注入数据源
DataSource
、注入事务管理器PlatformTransactionManager
,然后开启事务管理@EnableTransactionManagement
。2、上面三步执行完毕之后,就可以在需要使用事务管理的类或者方法上使用
@Transactional
注解即可。
二、Spring事务原理探究
Ⅰ、spring事务执行流程
1、首先,在容器启动的时候,会向容器中注册数据源、事务管理器、事务属性、事务拦截器等
2、Spring容器启动过程中,会为标注了 @Transactional
注解的类或方法创建一个代理对象
3、当执行具有事务管理的事务方法的时候,会执行代理对象中的代理方法(代理对象中保存了方法的增强器、目标对象、事务属性等信息)。
4、在执行目标方法前首先会执行事务拦截器链,然后执行事务拦截器链上的一个个拦截器(默认只有一个事务拦截器)
5、执行事务拦截器的时候,先从容器中获取该方法上的相关事务属性信息,然后获取事务管理器 PlatformTransactionManager
6、使用事务管理器开启一个事务
7、然后执行目标方法
①、如果目标方法正常执行,则利用事务管理器提交事务
②、如果目标方法执行出现异常,则利用事务管理器回滚事务
简而言之:容器会为标注了
@Transactional
注解的事务方法或类创建一个代理对象,每当要执行事务方法的时候,会去执行代理对象中的方法(先执行事务拦截器获取事务管理器、事务属性等,使用事务管理器开启事务,然后执行目标方法、目标方法正常执行,则使用事务管理器提交事务。若目标方法异常执行,则使用事务管理器回滚事务)。简单的说,spring的事务管理其实就是通过创建代理对象和拦截器,以及使用事务管理器帮我们自动的提交或回滚事务。不再需要我们手动的提交或回滚。
三、Spring事务源码解析
使用Spring的事务,最重要的一步就是:使用
@EnableTransactionManagement
注解开启事务管理,所以我们就以这个注解为突破口开始探究!探究的过程分两大步进行:
1、该注解向容器中注入了什么组件(bean)?
2、该组件在什么时候起了什么作用 ?
(一)、EnableTransactionManagement
1、查看注解EnableTransactionManagement
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// 可以看到在这里使用@Import和自定义Selector的方式在向容器中注册组件
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
// adviceMode默认就是PROXY,下面有用到
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
可以看到该注解使用了@Import注解和自定义Selector的方式向容器中导入组件,点击进入TransactionManagementConfigurationSelector中,查看该selector向容器中导入了什么组件
2、TransactionManagementConfigurationSelector
由上面的继承关系图可以看出 InfrastructureAdvisorAutoProxyCreator 类继承了
AbstractAutoProxyCreator
类,重点探究该类
②、AbstractAutoProxyCreator类
可重点关注该类的几个方法:
这四个方法作用时机主要是在bean的实例化前后和初始化前后。
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
// 该方法的作用就是创建一个代理对象,可自行深入探究
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
从上面代码可见,AutoProxyRegistrar
类的主要作用就是向容器中注入了 InfrastructureAdvisorAutoProxyCreator
组件,该组件是一个后置处理器,利用后置处理器机制在对象创建以后(初始化以后),包装对象,返回一个代理对象(代理对象中有包装事务拦截器、事务属性信息等)。
(三)、ProxyTransactionManagementConfiguration作用探究
由上面分析可知,EnableTransactionManagement注解向容器中注入了两个组件:AutoProxyRegistrar和ProxyTransactionManagementConfiguration,上面已经探究完了AutoProxyRegistrar的作用(bean创建的时候,给他创建代理对象),下面继续探究 ProxyTransactionManagementConfiguration 组件的作用时机以及作用。
1、ProxyTransactionManagementConfiguration源码
// 配置类
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
/**
* 注册事务增强器
*/
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
// 创建一个事务增强器
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
// 给增强器设置事务属性
advisor.setTransactionAttributeSource(transactionAttributeSource());
// 给增强器设置事务拦截器
advisor.setAdvice(transactionInterceptor());
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
// 将增强器注册到容器中
return advisor;
}
/**
* 注册事务属性(即:@Transactional(rollbackFor = Exception.class)注解里可用的属性)
* 上面的方法BeanFactoryTransactionAttributeSourceAdvisor会拿到这个事务属性并包装到增强器中
*/
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
/**
* 向容器中注入一个事务拦截器,他是一个方法拦截器,上面的方法
* BeanFactoryTransactionAttributeSourceAdvisor会拿到这个拦截器并包装到增强器中
*/
@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;
}
}
从上面的源码中可以看到,该类向容器中注入了三个组件:
**1、增强器:**BeanFactoryTransactionAttributeSourceAdvisor,容器启动的时候,增强器会被包装成拦截器链,当执行代理对象的方法的时候,就会先按照一定顺序执行拦截器链,即:这里是执行TransactionInterceptor里的invoke()方法。所以重点关注TransactionInterceptor。
**2、事务拦截器:**TransactionInterceptor ,用于拦截事务方法执行
**3、事务属性:**AnnotationTransactionAttributeSource,用于解析事务注解
这三个组件最后都会被包装到代理对象中!!!
2、关注事务拦截器(拦截到事务方法)
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
public Object invoke(final MethodInvocation invocation) throws Throwable {
// 获取目标类
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// 点进去,事务方法执行的地方,见下面的 《3》
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
}
3、事务方法的执行过程
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
// 重点方法
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.
// 使用getTransaction和提交/回滚调用的标准事务界定
// 创建事务
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// 这里执行事务方法,如果出现异常,则执行catch里面的方法通过事务管理器回滚。
// 可以跟进去深入研究,先调用拦截器,再调用目标方法(责任链模式调用)
retVal = invocation.proceedWithInvocation();
}catch (Throwable ex) {
// 如果事务方法执行异常,则在这里通过事务管理器回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}finally {
cleanupTransactionInfo(txInfo);
}
// 如果事务方法都成功执行完毕,则执行下面方法,通过事务管理器提交事务,点进去,见下面:
commitTransactionAfterReturning(txInfo);
return retVal;
}
// 省略。。。
}
事务方法执行过程:
1、首先获取事务属性(若获取不到事务属性,则说明这是一个非事务方法)
2、然后获取事务管理器
3、通过事务管理器执行事务方法
4、回滚或提交
到这里,ProxyTransactionManagementConfiguration组件的作用也清楚了:往容器中注入事务方法拦截器,拦截每一个事务方法的执行。在事务方法执行前,先获取事务属性、事务管理器等,通过事务管理器来开启一个事务,然后执行目标方法,然后再通过事务管理器提交或回滚!!!