事务处理拦截器的实现分析
接上篇:https://blog.csdn.net/convict_eva/article/details/83544328
通过上面的分析,很明确spring在事务方面aop是怎么玩的了。那么真正要处理事务是ProxyFactory.getObject() 方法返回的代理对象,通过调用代理对象的方法时,拦截器有一个invoker() 方法会被回调(aop的玩法)。
TransactionInterceptor.invoke() 方法源码:
public Object invoke(final 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...
//调用父类TransactionAspectSupport的方法
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
@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);
//根据TransactionProxyFactoryBean 的配置信息,获取事务处理器
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
//方法全限定名,如:com.masz.springtest.transaction.TransactionTXNameSpaceTest.add
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
/**
* 区分不同类型的PlatformTransactionManager,因为它们的调用方式不同
* CallbackPreferringPlatformTransactionManager 需要回调函数来实现事务的创建和提交,
* 对于其它的事务管理器,如 DataSourceTransactionManager 就不需要通过回调的方式来使用
*
*/
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
//使用标准事务处理
/**
* 创建事务,把创建事务过程中得到的信息放到TransactionInfo中去。
*/
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 {
//把与线程绑定的TransactionInfo 设置为OldTransationInfo
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, 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.
// RuntimeException 会导致事务回滚
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 {
//把与线程绑定的TransactionInfo 设置为OldTransationInfo
cleanupTransactionInfo(txInfo);
}
});
// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
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;
}
}
}
这里就到目标方法的调用和事务的提交了,和编程式事模板一样。
不同的是声明式事务基本不可见,由spring统一管理。前面说明了spring对aop事务的封装,
下来说明spring 是如何提供声明式事务处理的,spring封装了什么。
待续:spring 是如何提供声明式事务处理的,spring封装了什么。