一. 介绍
从前面介绍的,我们对 Spring AOP 已经有了较全面的了解,现在我们对 @Transactional 注解生成 AOP 代理对象的过程做一个解析;
我们直接在 AbstractAutoProxyCreator#wrapIfNecessary() 方法中创建代理对象处打一个断点,和 Spring AOP 相关的 Advisor 是 BeanFactoryTransactionAttributeSourceAdvisor;
BeanFactoryTransactionAttributeSourceAdvisor 是在 ProxyTransactionManagementConfiguration 中引用的,ProxyTransactionManagementConfiguration 的配置类如下:
@Configuration(proxyBeanMethods = false)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource,
TransactionInterceptor transactionInterceptor) {
// 使用的 pointcut 是: TransactionAttributeSourcePointcut
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
// TransactionAttributeSource 是用来获取事务元数据的
advisor.setTransactionAttributeSource(transactionAttributeSource);
// 针对 @Transactional 使用的 Advice
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>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) {
// 和 @Transactional 事务处理有关的 MethodInterceptor 是 TransactionInterceptor
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
// 设置事务管理器
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
二. 事务处理相关的pointcutAdvisor
从上面分析我们知道和 @Transactional 事务处理的 PointcutAdvisor 是 BeanFactoryTransactionAttributeSourceAdvisor;
它包含了 pointcut 和 advice,pointcut 用于匹配 bean 和对应的 method,advice 用于通知;
- TransactionAttributeSourcePointcut:用于匹配 @Transactional 标记的方法或类;
- TransactionInterceptor:用于处理事务方法的执行拦截;
对于 TransactionAttributeSourcePointcut,感兴趣可以看看,我们主要看 TransactionInterceptor 作为 MethodInterceptor 的 invoke() 逻辑;
三. TransactionInterceptor
事务的开启、提交、回滚,都是通过 TransactionInterceptor#invoke() 来进行拦截处理的;
TransactionInterceptor 实现了 MethodInterceptor 接口,它是一个 Advice;
// ------------------------ TransactionInterceptor ---------------------------
public class TransactionInterceptor
extends TransactionAspectSupport
implements MethodInterceptor, Serializable {
public TransactionInterceptor() {
}
public TransactionInterceptor(TransactionManager ptm,
TransactionAttributeSource tas) {
setTransactionManager(ptm);
setTransactionAttributeSource(tas);
}
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// 调用父类 TransactionAspectSupport 的 invokeWithinTransaction()
// 方法执行完后执行我们熟悉的 invocation.proceed() 继续触发调用链
return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
@Override
@Nullable
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
@Override
public Object getTarget() {
return invocation.getThis();
}
@Override
public Object[] getArguments() {
return invocation.getArguments();
}
});
}
}
TransactionAspectSupport 的 invokeWithinTransaction() 方法体很长,我们关注重点部分;
protected Object invokeWithinTransaction(Method method,
@Nullable Class<?> targetClass,
final InvocationCallback invocation) {
TransactionAttributeSource tas = getTransactionAttributeSource();
// 1. 根据目标类和方法获取 TransactionAttribute
// 其实这个类就是解析 @Transactional 注解得到的!!!
// 如果 TransactionAttribute 是 null,表示方法不需要事务
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 2. 获取事务管理器 TransactionManager
final TransactionManager tm = determineTransactionManager(txAttr);
// ...
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
String joinpointIdentification =methodIdentification(method,targetClass,txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// 3. 根据 TransactionManager、TransactionAttribute、方法标识等
// 创建得到 TransactionInfo 对象
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// 4. 执行 methodInvocation.proceed()
// 执行完一系列 MethodInterceptor 后最终会执行到目标方法,并得到方法返回值
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 5.1 如果执行过程中出现了异常
// 根据 @Transactional 注解信息决定是否进行回滚
// 不管是否回滚,都会将异常抛出
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 清理事务信息,暂不是重点
cleanupTransactionInfo(txInfo);
}
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// ...
}
// 5.2 执行过程中没有出现异常
// 对事务进行提交
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
// ...
}
}
重点是 3、5.1、5.2;下面我们逐个解析;
1. createTransactionIfNecessary()
根据 TransactionManager、TransactionAttribute、joinpointIdentification 方法标识等创建出 TransactionInfo 类对象,这里会根据事务管理器 TransactionManager 创建出事务状态对象 TransactionStatus;
// ----------------------- TransactionAspectSupport ----------------------------
protected TransactionInfo createTransactionIfNecessary(PlatformTransactionManager tm,
TransactionAttribute txAttr,
String joinpointIdentification) {
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);
}
else {
// ...
}
}
// 2. 根据 tm、txAttr、joinpointIdentification、transactionStatus
// 创建出 TransactionInfo 对象
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
2. completeTransactionAfterThrowing()
// ------------------------- TransactionAspectSupport ---------------------------
protected void completeTransactionAfterThrowing(TransactionInfo txInfo,
Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
// 1. 如果当前异常需要需要回滚,那么回滚事务
if (txInfo.transactionAttribute != null &&
txInfo.transactionAttribute.rollbackOn(ex)) {
// 回滚事务
// tm.rollback(transactionStatus)
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
} else {
// 当前异常不需要回滚,不回滚事务
// 提交事务
// tm.commit(transactionStatus)
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
}
如果当前异常需要回滚,那么回滚事务;
如果当前异常不需要回滚,那么不回滚事务,提交事务;
我们看下 rollbackOn(ex) 的逻辑;
// ------------------------ RuleBasedTransactionAttribute ----------------------
public boolean rollbackOn(Throwable ex) {
RollbackRuleAttribute winner = null;
int deepest = Integer.MAX_VALUE;
// 1. 根据 rollbackRules 匹配异常 ex
// rollbackFor 属性对应的是 RollbackRuleAttribute
// noRollbackFor 属性对应的是 NoRollbackRuleAttribute
if (this.rollbackRules != null) {
for (RollbackRuleAttribute rule : this.rollbackRules) {
int depth = rule.getDepth(ex);
if (depth >= 0 && depth < deepest) {
deepest = depth;
winner = rule;
}
}
}
// 2. 如果都不匹配的话,调用父类的匹配模式
if (winner == null) {
return super.rollbackOn(ex);
}
// 3. 如果异常匹配到了 RollbackRuleAttribute,返回 true,此时需要回滚
// 如果异常匹配到了 NoRollbackRuleAttribute,返回 false,此时不需要回滚
return !(winner instanceof NoRollbackRuleAttribute);
}
// 2. 如果都不匹配的话,调用父类的匹配模式
// ----------------------- DefaultTransactionAttribute -------------------------
public boolean rollbackOn(Throwable ex) {
// 如果当前异常是 RuntimeException 或者 Error 类型的,返回 true,需要回滚
// 其他异常如受检异常,返回 false,不回滚
return (ex instanceof RuntimeException || ex instanceof Error);
}
这么看可能有些乱,需要仔细 debug 看看 RuleBasedTransactionAttribute 的流程,我们举几个例子看看:
1、例1:@Transactional 没有 rollbackFor,也没有 noRollbackFor;
此时 NullPointerException、IllegalArgumentException 都是 RuntimeException 类型,会走 DefaultTransactionAttribute#rollbackOn(),两种异常均会回滚;
@Transactional
public User updateUser(User user) throws IOException {
int count = userMapper.updateUser(user);
if (user.getId() == 4) {
throw new NullPointerException("模拟出现空指针异常");
} else if (user.getId() == 5) {
throw new IllegalArgumentException();
}
return user;
}
2、例2:@Transactional 有 rollbackFor,没有 noRollbackFor;
出现 NullPointerException 异常会回滚事务;
出现 IllegalArgumentException 异常也会回滚事务;是不是很纳闷,IllegalArgumentException 不在 rollbackFor 列表啊,事务应该不回滚才对啊,错啦!我们按 RuleBasedTransactionAttribute#rollbackOn() 看一下,IllegalArgumentException 不会匹配到 RollbackRuleAttribute,winner == null,会走 DefaultTransactionAttribute#rollbackOn(),IllegalArgumentException 属于 RuntimeException,事务需要回滚;
@Transactional(rollbackFor = {NullPointerException.class})
public User updateUser(User user) throws IOException {
int count = userMapper.updateUser(user);
if (user.getId() == 4) {
throw new NullPointerException("模拟出现空指针异常");
} else if (user.getId() == 5) {
throw new IllegalArgumentException();
}
return user;
}
3、例3:@Transactional 有 rollbackFor,也有 noRollbackFor;
出现 NullPointerException 异常会回滚事务;
出现 IllegalArgumentException 异常不会回滚事务;按 RuleBasedTransactionAttribute#rollbackOn() 看一下,IllegalArgumentException 会匹配到 NoRollbackRuleAttribute,winner != null,返回值为 false,不回滚事务;
@Transactional(rollbackFor = {NullPointerException.class},
noRollbackFor = {IllegalArgumentException.class})
public User updateUser(User user) throws IOException {
int count = userMapper.updateUser(user);
if (user.getId() == 4) {
throw new NullPointerException("模拟出现空指针异常");
} else if (user.getId() == 5) {
throw new IllegalArgumentException();
}
return user;
}
4、例4:@Transactional,没有 rollbackFor,也没有 noRollbackFor,且发生的是受检异常;
如上分析,RuleBasedTransactionAttribute#rollbackOn() 看一下,IOException 不会匹配到 RollbackRuleAttribute、NoRollbackRuleAttribute,winner == null,会走 DefaultTransactionAttribute#rollbackOn(),IOException 属于 RuntimeException,也不属于 Error,返回值 false,不回滚事务;
至此,事务回滚结束!
3. commitTransactionAfterReturning()
提交事务,这个我们在上面就分析过了;
// ------------------------- TransactionAspectSupport ----------------------------
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
// 提交事务
// tm.commit(transactionStatus)
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
四. 手动事务
首先,你需要获取一个 PlatformTransactionManager 的实例,这个实例通常在 Spring 的配置中定义;如果你使用的是 JDBC,可能会有一个 JdbcTransactionManager;如果是使用 Hibernate,则可能是HibernateTransactionManager;
- TransactionDefinition:定义了事务的隔离级别、传播行为等属性;DefaultTransactionDefinition是一个默认实现,你也可以根据需要自定义;
- TransactionStatus:表示事务的状态,包括是否新开始的事务、是否已提交或回滚等;
- PlatformTransactionManager:提供了事务的管理接口,包括开始事务、提交事务、回滚事务等方法;
@Autowired
private PlatformTransactionManager transactionManager;
public void update() {
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 你的业务逻辑代码放在这里
// ...
// 业务逻辑成功,提交事务
transactionManager.commit(status);
} catch (Exception ex) {
// 业务逻辑失败,回滚事务
transactionManager.rollback(status);
throw ex; // 可以选择重新抛出异常
}
}
至此,手动事务完成;