前文:今天我们主要来学习一下Spring事务的源码解析,主要讲的是Spring的申明式事务的讲解。申明式事务管理: 基于Spring AOP实现。其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。申明式事务管理不需要入侵代码,通过@Transactional就可以进行事务操作,且大部分业务都可以满足,推荐使用。
1、@EnableTransactionManagement 申明式事务的启用注解,也是源码解析的入口。
2、TransactionManagementConfigurationSelector 事务管理配置导入选择器。
3、AutoProxyRegistrar:给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件;利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用。
4、ProxyTransactionManagementConfiguration:就是一个配置类,定义了事务增强器。
5、InfrastructureAdvisorAutoProxyCreator 一个BeanPostProcessor.class的子类,也就是后置处理器,它可以在Spring初始化bean之前或之后进行功能增强。
6、TransactionAttributeSource 事务注册解析器 。解析@Transactional()的里面的属性和传播行为。
7、TransactionInterceptor 事务拦截器,生成动态类后,执行目标方法时,进行拦截和调用链的执行。
使用EnableTransactionManagement注解可以开启Spring事务,而EnableTransactionManagement源代码如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
/**
* 默认是使用代理的通知模式
*/
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
了解TransactionManagementConfigurationSelector.class的功能:
该类实现了ImportSelector接口,通过覆写selectImports()方法,手动将java类注册到Spring框架的IOC容器中。
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY: // 默认就是Proxy模式
return new String[] {AutoProxyRegistrar.class.getName(),ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
通过这个类,Spring会将InfrastructureAdvisorAutoProxyCreator.class注入到IOC容器,然后请看该类类图:
由图知InfrastructureAdvisorAutoProxyCreator.class是一个BeanPostProcessor.class的子类,理论上它可以在Spring初始化bean之前或之后进行功能增强,Sping框架原生选择是之后增强,具体的增强方法是在AbstractAutoProxyCreator#postProcessAfterInitialization()方法。进行包装增强。创建代理对象==
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
/** Wrap the given bean if necessary
* 对bean进行包装,其实就是创建代理对象
*/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 省略。。。。
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理,jdk动态代理或者cglib代理
Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
}
上述代码的作用就是,Spring在bean初始化之后,会判断该bean是否需要创建一个代理对象,如果需要,就会使用jdk动态代理或者cglib创建一个代理类(这一块不是本篇文章分析的重点)。
定义了一个advisor,设置事务属性、设置事务拦截器TransactionInterceptor、设置顺序。核心就是事务拦截器TransactionInterceptor。
TransactionInterceptor使用通用的spring事务基础架构实现“声明式事务”,继承自TransactionAspectSupport类(该类包含与Spring的底层事务API的集成),实现了MethodInterceptor接口。spring类图如下:
事务拦截器的拦截功能就是依靠实现了MethodInterceptor接口,熟悉spring的同学肯定很熟悉MethodInterceptor了,这个是spring的方法拦截器,主要看invoke方法:
@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// 调用TransactionAspectSupport的 invokeWithinTransaction方法
return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
@Override
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
});
}
TransactionInterceptor复写MethodInterceptor接口的invoke方法,并在invoke方法中调用了父类TransactionAspectSupport的invokeWithinTransaction()方法,源码如下:
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {
// 如果transaction attribute为空,该方法就是非事务(非编程式事务)
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 {
// 这里就是一个环绕增强,在这个proceed前后可以自己定义增强实现
// 方法执行
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 根据事务定义的,该异常需要回滚就回滚,否则提交事务
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {//清空当前事务信息,重置为老的
cleanupTransactionInfo(txInfo);
}//返回结果之前提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
// 编程式事务:(回调偏向)
else {
final ThrowableHolder throwableHolder = new ThrowableHolder();
// 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)) {
// 如果是运行时异常返回
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}// 如果是其它异常都抛ThrowableHolderException
else {
throw new ThrowableHolderException(ex);
}
}// 如果不需要回滚
else {
// 定义异常,最终就直接提交事务了
throwableHolder.throwable = ex;
return null;
}
}
finally {//清空当前事务信息,重置为老的
cleanupTransactionInfo(txInfo);
}
}
});
// 上抛异常
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
}
}
如上提所示,PlatformTransactionManager顶级接口定义了最核心的事务管理方法,下面一层是AbstractPlatformTransactionManager抽象类,实现了PlatformTransactionManager接口的方法并定义了一些抽象方法,供子类拓展。最后下面一层是2个经典事务管理器:
即JDBC单数据库事务管理器,基于Connection实现,
即多数据库事务管理器(又叫做分布式事务管理器),其实现了JTA规范,使用XA协议进行两阶段提交。
我们这里只看基于JDBC connection的DataSourceTransactionmanager源码。
PlatformTransactionManager接口:
public interface PlatformTransactionManager {
// 获取事务状态
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
// 事务提交
void commit(TransactionStatus status) throws TransactionException;
// 事务回滚
void rollback(TransactionStatus status) throws TransactionException;
}
源代码如下:
@Override
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
if (definition == null) {
definition = new DefaultTransactionDefinition();
}
// 如果当前已经存在事务
if (isExistingTransaction(transaction)) {
// 根据不同传播机制不同处理
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// 超时不能小于默认值
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
// 当前不存在事务,传播机制=MANDATORY(支持当前事务,没事务报错),报错
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}// 当前不存在事务,传播机制=REQUIRED/REQUIRED_NEW/NESTED,这三种情况,需要新开启事务,且加上事务同步
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {// 是否需要新开启同步// 开启// 开启
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);// 开启新事务
prepareSynchronization(status, definition);//预备同步
return status;
}
catch (RuntimeException ex) {
resume(null, suspendedResources);
throw ex;
}
catch (Error err) {
resume(null, suspendedResources);
throw err;
}
}
else {
// 当前不存在事务当前不存在事务,且传播机制=PROPAGATION_SUPPORTS/PROPAGATION_NOT_SUPPORTED/PROPAGATION_NEVER,这三种情况,创建“空”事务:没有实际事务,但可能是同步。
//警告:定义了隔离级别,但并没有真实的事务初始化,隔离级别被忽略有隔离级别但是并没有定义实际的事务初始化,有隔离级别但是并没有定义实际的事务初始化,
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + definition);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
源码分成了2条处理线,
(1).当前已存在事务:isExistingTransaction()判断是否存在事务,存在事务handleExistingTransaction()根据不同传播机制不同处理
(2).当前不存在事务: 不同传播机制不同处理handleExistingTransaction()。
SqlSessionSynchronization是SqlSessionUtils的一个内部类,继承自TransactionSynchronizationAdapter抽象类,实现了事务同步接口TransactionSynchronization。TransactionSynchronization接口定义了事务操作时的对应资源的(JDBC事务那么就是SqlSessionSynchronization)管理方法:
// 挂起事务
void suspend();
// 唤醒事务
void resume();
void flush();
// 提交事务前
void beforeCommit(boolean readOnly);
// 提交事务完成前
void beforeCompletion();
// 提交事务后
void afterCommit();
// 提交事务完成后
void afterCompletion(int status);
**
**
AbstractPlatformTransactionManager中rollback源码:
public final void rollback(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;
processRollback(defStatus);
}
processRollback源码如下:
private void processRollback(DefaultTransactionStatus status) {
try {
try {// 解绑当前线程绑定的会话工厂,并关闭会话
triggerBeforeCompletion(status);
if (status.hasSavepoint()) {// 1.如果有保存点,即嵌套式事务
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}//回滚到保存点
status.rollbackToHeldSavepoint();
}//2.如果就是一个简单事务
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}//回滚核心方法
doRollback(status);
}//3.当前存在事务且没有保存点,即加入当前事务的
else if (status.hasTransaction()) {//如果已经标记为回滚 或 当加入事务失败时全局回滚(默认true)
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {//debug时会打印:加入事务失败-标记已存在事务为回滚
logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
}//设置当前connectionHolder:当加入一个已存在事务时回滚
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");
}
}
catch (RuntimeException ex) {//关闭会话,重置SqlSessionHolder属性
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw ex;
}
catch (Error err) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw err;
}
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
}
finally {、、解绑当前线程
cleanupAfterCompletion(status);
}
}
申明式事务管理不需要入侵代码,是基于Aop,具体而言是通过一个TransactionInterceptor的拦截器来实现。通过@Transactional就可以进行事务操作,更快捷而且简单(尤其是配合spring boot自动配置,可以说是精简至极!),且大部分业务都可以满足,推荐使用。
**注意:**而在同一个class中,方法B调用方法A,调用的是原对象的方法,而不通过代理对象。所以Spring无法切到这次调用,也就无法通过注解保证事务性了。 也就是说,在同一个类中的方法调用,则不会被方法拦截器拦截到,因此事务不会起作用。