系列文章目录
前言
上一篇介绍了spring事务管理的几个组件,这一篇我们从@EnableTransactionManagement注解开始看spring的事务管理
一、springframework的事务管理
从@EnableTransactionManagement注解开始,spring就开启了事务管理,所以我们从这里开始看源码
1.引入组件
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
。。。
}
通过引入TransactionManagementConfigurationSelector最终引入了两个组件:
1)注册了一个BPP:InfrastructureAdvisorAutoProxyCreator
这个BPP
2)注册了一个Advisor:BeanFactoryTransactionAttributeSourceAdvisor。而BeanFactoryTransactionAttributeSourceAdvisor是一个PointcutAdvisor的实现类,我们在AOP那一篇讲过PointcutAdvisor的2个关键方法,就是获取pointcut和advice。BeanFactoryTransactionAttributeSourceAdvisor的实现如下:
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
//设置pointcut的属性,pointcut的matches方法就是由transactionAttributeSource完成的
advisor.setTransactionAttributeSource(transactionAttributeSource);
//设置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) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
@Override
public boolean matches(Method method, Class<?> targetClass) {
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
2.解析@Transactional注解
我们在AOP那一篇讲过初始化后方法创建代理对象,同样,在执行InfrastructureAdvisorAutoProxyCreator这个BPP的初始化后方法时,会创建事务的代理对象
1)获取所有候选的Advisor
2)从候选Advisor中获取可以用于该bean的advisors(执行pointcut的matches方法)
3)对符合的bean创建代理对象
所以,BeanFactoryTransactionAttributeSourceAdvisor作为候选的advisor,执行其pointcut的matches方法,最终执行的是TransactionAttributeSource 的getTransactionAttribute方法,筛选的逻辑就是判断方法或类或接口方法或接口上是否有@Transactional注解
最终对方法或类或接口方法或接口上有@Transactional注解的创建了代理对象
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
// First, see if we have a cached value.
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// Value will either be canonical value indicating there is no transaction attribute,
// or an actual transaction attribute.
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
return cached;
}
}
else {
// We need to work it out.
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// Put it in the cache.
if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
}
if (logger.isTraceEnabled()) {
logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
3.调用入口
同AOP
1)遍历候选的advisor,将匹配要调用方法的advisor的advice取出来,生成拦截器链
2)按照拦截器链顺序递归调用
此时对于BeanFactoryTransactionAttributeSourceAdvisor来说,只有方法上有@Transactional注解才会取出BeanFactoryTransactionAttributeSourceAdvisor的advice生成拦截器链进行调用
调用入口就是TransactionInterceptor的invoke方法
public Object invoke(MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
//spring事务调用入口
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
4.事务执行
//获取@Transactional注解上配置的属性
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
...
//获取事务管理器
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
//获取切入点
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
//1.创建事务
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
//2.执行事务中的业务
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
//3.回滚事务
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
//4.清理事务
cleanupTransactionInfo(txInfo);
}
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
//提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
1)创建事务
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
这里创建了TransactionInfo ,其实就是对TransactionManager和TansactionStatus的封装(前面讲过TransactionManager中创建事务时返回的是TansactionStatus)。TransactionInfo多封装了transactionAttribute(@Transactional中的属性,比如隔离级别、事务的传播方式、rollbackon属性)、joinpointIdentification(事务的名称)、oldTransactionInfo(上层事务信息)。我们在使用TranactionTemplate时需要手动set隔离级别、事务的传播方式、事务的名称。那么这里就都封装到TransactionInfo中了。
private final PlatformTransactionManager transactionManager;
private final TransactionAttribute transactionAttribute;
private final String joinpointIdentification;
private TransactionStatus transactionStatus;
private TransactionInfo oldTransactionInfo;
而oldTransactionInfo是上层事务信息的引用,形成了一个事务信息的链表,用于后续恢复上层事务。在创建TransactionInfo 时,先获取上层TransactionInfo,再将本层的TransactionInfo放到ThreadLocal中
private void bindToThread() {
this.oldTransactionInfo = transactionInfoHolder.get();
transactionInfoHolder.set(this);
}
2)执行事务中的信息
这里就是递归执行
3)回滚事务
completeTransactionAfterThrowing(txInfo, ex);
上面说了TransactionInfo是对TansactionStatus的封装,所以这里回滚事务的逻辑本质是调用TransactionManager回滚TansactionStatus的方法,只是多了对rollbackOn判断的功能,也就是指定回滚的异常类型。如果不是指定的回滚类型,那么就提交事务。如何回滚和提交,前面讲TransactionManager已经讲过
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
...
}
else {
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
...
}
4)清理事务
cleanupTransactionInfo(txInfo);
就是恢复上层的TransactionInfo,也就是将oldTransactionInfo重新放到ThreadLocal中
private void restoreThreadLocalStatus() {
transactionInfoHolder.set(this.oldTransactionInfo);
}
5)提交事务
commitTransactionAfterReturning(txInfo);
就是调用TransactionManager对TransactionStatus进行提交,前面已经讲过了
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
5.小结:
1)springframework的事务管理通过引入2个组件将@Transacional注解的方法解析成代理对象,在代理对象中开始事务的执行流程
2)执行时,通过TransactionInfo封装了TransactionManager和TansactionStatus,最终还是执行的TransactionManager中的事务方法,只是多了一些功能
二、事务的生命周期方法
事务的生命周期方法主要涉及事务的创建、提交、回滚和销毁等阶段。
TransactionSynchronizationManager使用示例:
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void testA() {
TransactionSynchronizationManag事务的er.registerSynchronization(new TransactionSynchronization() {
@Override
public void suspend() {
System.out.println("A被挂起了");
}
@Override
public void resume() {
System.out.println("A被恢复了");
}
});
jdbcTemplate.update("update customer set cust_name='snow2' where id = 1");
}
就不展开介绍了
三、TransactionInfo封装的功能
1.事务的隔离级别
在Spring中,可以通过 @Transactional 注解或编程式事务管理来设置事务的隔离级别。
@Transactional(isolation = Isolation.READ_COMMITTED)
public void someMethod() {
// 业务逻辑
}
2.事务的传播方式
@Service
public class OrderService {
@Transactional(propagation = Propagation.REQUIRED)
public void placeOrder(Order order) {
// 如果当前有事务,则加入;否则新建事务
// 业务逻辑...
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateInventory(Product product) {
// 始终新建事务,挂起当前事务(如果有)
// 业务逻辑...
}
}
3.指定回滚的异常类型
rollbackon属性:只有出现这些异常类型时才会回滚
noRollbackFor属性:出现这类异常时不会滚
@Transactional(rollbackon = {SQLException.class, InsufficientBalanceException.class})
public void transferMoney(Account from, Account to, double amount) throws InsufficientBalanceException {
// 当抛出 SQLException 或 InsufficientBalanceException 时,事务回滚
}
@Transactional(noRollbackFor = {IllegalArgumentException.class})
public void updatePrice(Product product, double newPrice) {
// 即使抛出 IllegalArgumentException,事务也不会回滚
}
四、事务代理与AOP代理是否冲突
- @EnableTransactionManagement注解注册了一个BPP:InfrastructureAdvisorAutoProxyCreator,我们在介绍AOP时,开启AOP,使用@EnableAspectJAutoProxy注解注册了AnnotationAwareAspectJAutoProxyCreator,这两个BPP都在初始化后方法中发挥作用,会不会产生冲突呢(比如事务代理了一遍,AOP又代理了一遍,是不是事务会开启2次)?
我们先看看@EnableTransactionManagement注解是怎么注册InfrastructureAdvisorAutoProxyCreator的
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
AdviceMode mode() default AdviceMode.PROXY;
}
//TransactionManagementConfigurationSelector的selectImports方法
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
//上面看到EnableTransactionManagement的mode属性默认是PROXY,所以走这里
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
//AutoProxyRegistrar
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
for (String annType : annTypes) {
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (candidate == null) {
continue;
}
Object mode = candidate.get("mode");
Object proxyTargetClass = candidate.get("proxyTargetClass");
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
candidateFound = true;
if (mode == AdviceMode.PROXY) {
//在这里注册
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
}
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
1)先通过导入ImportSelector的方式注册了AutoProxyRegistrar
2)AutoProxyRegistrar是一个ImportBeanDefinitionRegistrar,在registerBeanDefinitions方法中
调用registerAutoProxyCreatorIfNecessary方法对InfrastructureAdvisorAutoProxyCreator进行注册,
继续看registerOrEscalateApcAsRequired方法
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
//如果存在,则比较优先级
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
//如果不存在,则创建beanName为AUTO_PROXY_CREATOR_BEAN_NAME的BeanDefinition
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
3)在registerOrEscalateApcAsRequired方法中会判断是否有beanName为AUTO_PROXY_CREATOR_BEAN_NAME的BeanDefinition,如果有,则比较优先级,留下优先级高的,如果不存在则新建
@EnableAspectJAutoProxy注解注册AnnotationAwareAspectJAutoProxyCreator也是类似的逻辑,就不贴代码了
所以,容器中只会留下优先级最高的那个,那么就不会产生冲突了
总结
- spring通过@EnableTransactionManagement开启事务,引入了2个组件InfrastructureAdvisorAutoProxyCreator和BeanFactoryTransactionAttributeSourceAdvisor。
1)InfrastructureAdvisorAutoProxyCreator用于初始化后进行AOP
2)BeanFactoryTransactionAttributeSourceAdvisor中有拦截器TransactionInterceptor用于开启、提交、回滚事务。有PointCut用于判断对哪些类生成代理(判断方法或类或接口方法或接口上是否有@Transactional注解,有就创建代理) - 方法调用:同AOP,将匹配方法的advisor中的拦截器生成拦截器链,最终执行TransactionInterceptor的invoke方法。执行时,通过TransactionInfo封装了TransactionManager和TansactionStatus,最终还是执行的TransactionManager中的事务方法,只是多了一些功能,比如隔离级别、事务的传播方式、rollbackon属性