前言 上一篇 我们介绍了spring-tx
中的底层抽象,本篇我们一起来看看围绕这些抽象概念spring-tx
是如何打造出声明式事务的吧。笼统的说,spring-tx-5.2.6.RELEASE
的实现主要分为两个部分:
PlatformTransactionManager
抽象下的事务管理细节
基于spring-aop
的拦截器如何将普通方法增强为事务方法的
这两部分彼此独立又相互成就,并且每个部分都有着大量的源码支撑,本篇我们先来分析spring-tx
中的AOP部分吧。
一切从EnableTransactionManagement说起 EnableTransactionManagement
注解想必大家都很熟悉了,它是启用 Spring 中注释驱动的事务管理功能的关键。
@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 ; }
EnableTransactionManagement
注解的主要作用是向容器中导入TransactionManagementConfigurationSelector
,至于注解中定义的几个属性在Spring AOP源码解析 中有过详细分析,这里就不再赘述了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector <EnableTransactionManagement > { @Override protected String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}; case ASPECTJ: return new String[] {determineTransactionAspectClass()}; default : return null ; } } private String determineTransactionAspectClass () { return (ClassUtils.isPresent("javax.transaction.Transactional" , getClass().getClassLoader()) ? TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME : TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME); } }
由于我们并没有使用AspectJ
,因此导入容器的自然是ProxyTransactionManagementConfiguration
这个配置类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 @Configuration public abstract class AbstractTransactionManagementConfiguration implements ImportAware { @Nullable protected AnnotationAttributes enableTx; @Nullable protected TransactionManager txManager; @Override public void setImportMetadata (AnnotationMetadata importMetadata) { this .enableTx = AnnotationAttributes.fromMap( importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false )); if (this .enableTx == null ) { throw new IllegalArgumentException("@EnableTransactionManagement is not present on importing class " + importMetadata.getClassName()); } } @Autowired(required = false) void setConfigurers (Collection<TransactionManagementConfigurer> configurers) { if (CollectionUtils.isEmpty(configurers)) { return ; } if (configurers.size() > 1 ) { throw new IllegalStateException("Only one TransactionManagementConfigurer may exist" ); } TransactionManagementConfigurer configurer = configurers.iterator().next(); this .txManager = configurer.annotationDrivenTransactionManager(); } @Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public static TransactionalEventListenerFactory transactionalEventListenerFactory () { return new TransactionalEventListenerFactory(); } }@Configuration(proxyBeanMethods = false) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) 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(); advisor.setTransactionAttributeSource(transactionAttributeSource); 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; } }
这个配置类的核心是向容器中导入一个类型为BeanFactoryTransactionAttributeSourceAdvisor
的Bean。这是一个PointcutAdvisor
,它的Pointcut
是TransactionAttributeSourcePointcut
,Advice
是TransactionInterceptor
。
TransactionAttributeSourcePointcut
利用TransactionAttributeSource
解析@Transactional
注解的能力来选取标注了@Transactional
注解的方法,而TransactionInterceptor
则根据应用提出的需求(来自对@Transactional
注解的解析)将方法增强为事务方法,因此BeanFactoryTransactionAttributeSourceAdvisor
可以识别出那些标注了@Transactional
注解的方法,为它们应用上事务相关功能。
事务拦截器的工作原理 TransactionAttributeSource TransactionInterceptor
能对方法进行增强,但是它却不知道该如何增强,比如是为方法新开一个独立事务还是沿用已有的事务?什么情况下需要回滚,什么情况下不需要?必须有一个『人』告诉它该如何增强,这个『人』便是TransactionAttributeSource
。
@Transactional
注解定义了事务的基础信息,它表达了应用程序期望的事务形态。TransactionAttributeSource
的主要作用就是解析@Transactional
注解,提取其属性,包装成TransactionAttribute
,这样TransactionInterceptor
的增强便有了依据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public interface TransactionAttributeSource { default boolean isCandidateClass (Class<?> targetClass) { return true ; } @Nullable TransactionAttribute getTransactionAttribute (Method method, @Nullable Class<?> targetClass) ; }
前面我们已经见过,spring-tx
使用AnnotationTransactionAttributeSource
来做具体的解析工作,其父类AbstractFallbackTransactionAttributeSource
定义了解析TransactionAttribute
的优先级,核心方法是computeTransactionAttribute(...)
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @Nullable protected TransactionAttribute computeTransactionAttribute (Method method, @Nullable Class<?> targetClass) { if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null ; } Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass); TransactionAttribute txAttr = findTransactionAttribute(specificMethod); if (txAttr != null ) { return txAttr; } txAttr = findTransactionAttribute(specificMethod.getDeclaringClass()); if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { return txAttr; } if (specificMethod != method) { txAttr = findTransactionAttribute(method); if (txAttr != null ) { return txAttr; } txAttr = findTransactionAttribute(method.getDeclaringClass()); if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { return txAttr; } } return null ; }
AnnotationTransactionAttributeSource
默认只解析public
修饰的方法,这也是导致@Transactional
注解失效的一个原因,除此之外它还实现了父类中定义的两个模板方法:
findTransactionAttribute(Method method)
,获取定义在方法上的事务属性
findTransactionAttribute(Class<?> clazz)
,获取定义在类上的事务属性
同时为了支持 EJB 中定义的javax.ejb.TransactionAttribute
和 JTA 中定义的javax.transaction.Transactional
注解,AnnotationTransactionAttributeSource
选择将实际的提取工作代理给TransactionAnnotationParser
。Spring 提供的@Transactional
注解由SpringTransactionAnnotationParser
进行解析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 public class SpringTransactionAnnotationParser implements TransactionAnnotationParser , Serializable { @Override public boolean isCandidateClass (Class<?> targetClass) { return AnnotationUtils.isCandidateClass(targetClass, Transactional.class); } @Override @Nullable public TransactionAttribute parseTransactionAnnotation (AnnotatedElement element) { AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes( element, Transactional.class, false , false ); if (attributes != null ) { return parseTransactionAnnotation(attributes); } else { return null ; } } protected TransactionAttribute parseTransactionAnnotation (AnnotationAttributes attributes) { RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); Propagation propagation = attributes.getEnum("propagation" ); rbta.setPropagationBehavior(propagation.value()); Isolation isolation = attributes.getEnum("isolation" ); rbta.setIsolationLevel(isolation.value()); rbta.setTimeout(attributes.getNumber("timeout" ).intValue()); rbta.setReadOnly(attributes.getBoolean("readOnly" )); rbta.setQualifier(attributes.getString("value" )); List<RollbackRuleAttribute> rollbackRules = new ArrayList<>(); for (Class<?> rbRule : attributes.getClassArray("rollbackFor" )) { rollbackRules.add(new RollbackRuleAttribute(rbRule)); } for (String rbRule : attributes.getStringArray("rollbackForClassName" )) { rollbackRules.add(new RollbackRuleAttribute(rbRule)); } for (Class<?> rbRule : attributes.getClassArray("noRollbackFor" )) { rollbackRules.add(new NoRollbackRuleAttribute(rbRule)); } for (String rbRule : attributes.getStringArray("noRollbackForClassName" )) { rollbackRules.add(new NoRollbackRuleAttribute(rbRule)); } rbta.setRollbackRules(rollbackRules); return rbta; } @Override public boolean equals (@Nullable Object other) { return (this == other || other instanceof SpringTransactionAnnotationParser); } @Override public int hashCode () { return SpringTransactionAnnotationParser.class.hashCode(); } }
SpringTransactionAnnotationParser
的源码还是很简单的,它使用AnnotatedElementUtils
工具类定义的find
语义来获取@Transactional
注解信息。RuleBasedTransactionAttribute
中rollbackOn(...)
的实现还是挺有意思的,其它的都平平无奇。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 @Override public boolean rollbackOn (Throwable ex) { if (logger.isTraceEnabled()) { logger.trace("Applying rules to determine whether transaction should rollback on " + ex); } RollbackRuleAttribute winner = null ; int deepest = Integer.MAX_VALUE; if (this .rollbackRules != null ) { for (RollbackRuleAttribute rule : this .rollbackRules) { int depth = rule.getDepth(ex); if (depth >= 0 && depth < deepest) { deepest = depth; winner = rule; } } } if (logger.isTraceEnabled()) { logger.trace("Winning rollback rule is: " + winner); } if (winner == null ) { logger.trace("No relevant rollback rule found: applying default rules" ); return super .rollbackOn(ex); } return !(winner instanceof NoRollbackRuleAttribute); }
RollbackRuleAttribute
是用来确定在发生特定类型的异常(或其子类)时是否应该回滚,而NoRollbackRuleAttribute
继承自RollbackRuleAttribute
,但表达的是相反的含义。RollbackRuleAttribute
持有某个异常的名称,通过getDepth(Throwable ex)
算法来计算指定的Throwable
和持有的异常在继承链上的距离。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public int getDepth (Throwable ex) { return getDepth(ex.getClass(), 0 ); }private int getDepth (Class<?> exceptionClass, int depth) { if (exceptionClass.getName().contains(this .exceptionName)) { return depth; } if (exceptionClass == Throwable.class) { return -1 ; } return getDepth(exceptionClass.getSuperclass(), depth + 1 ); }
TransactionInterceptor
程序猿只有在拿到需求以后才能开工,TransactionInterceptor
也一样,有了TransactionAttributeSource
之后就可以有依据的增强了。观察类图,TransactionInterceptor
实现了MethodInterceptor
接口,那么自然要实现接口中的方法:
1 2 3 4 5 6 7 8 9 10 @Override @Nullable public Object invoke (MethodInvocation invocation) throws Throwable { Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null ); return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed); }
可以看到,TransactionInterceptor
本身是没有实现任何逻辑的,它更像一个适配器。这样分层以后,TransactionAspectSupport
理论上就可以支持任意类型的Advice
而不只是MethodInterceptor
。实现上TransactionAspectSupport
确实也考虑了这一点,我们马上就会看到。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 @Nullable protected Object invokeWithinTransaction (Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable { TransactionAttributeSource tas = getTransactionAttributeSource(); final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null ); final TransactionManager tm = determineTransactionManager(txAttr); PlatformTransactionManager ptm = asPlatformTransactionManager(tm); final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification); Object retVal; try { retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); } commitTransactionAfterReturning(txInfo); return retVal; }
invokeWithinTransaction(...)
的流程还是非常清晰的:
获取TransactionManager
和TransactionAttribute
,这两兄弟一个决定了能否开启事务,另一个决定了如何开启事务
尝试开启事务
try
块包裹住目标方法的执行,根据执行结果进行相应的处理——提交或回滚
第一步前文已经分析过了,我们来看第二步。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 protected TransactionInfo createTransactionIfNecessary (@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, final 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 ) { status = tm.getTransaction(txAttr); } else { if (logger.isDebugEnabled()) { logger.debug("Skipping transactional joinpoint [" + joinpointIdentification + "] because no transaction manager has been configured" ); } } } return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status); }protected TransactionInfo prepareTransactionInfo (@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, String joinpointIdentification, @Nullable TransactionStatus status) { TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification); if (txAttr != null ) { if (logger.isTraceEnabled()) { logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]" ); } txInfo.newTransactionStatus(status); } else { if (logger.isTraceEnabled()) { logger.trace("No need to create transaction for [" + joinpointIdentification + "]: This method is not transactional." ); } } txInfo.bindToThread(); return txInfo; }
TransactionInfo
是一个非常简单的类,我们就不费什么笔墨去分析它了。接着看第三步,这一步涉及到两个不同的操作——提交或回滚。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 protected void commitTransactionAfterReturning (@Nullable TransactionInfo txInfo) { if (txInfo != null && txInfo.getTransactionStatus() != null ) { if (logger.isTraceEnabled()) { logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]" ); } txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); } }protected void completeTransactionAfterThrowing (@Nullable TransactionInfo txInfo, Throwable ex) { if (txInfo != null && txInfo.getTransactionStatus() != null ) { if (logger.isTraceEnabled()) { logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex); } if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) { try { txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); } catch (TransactionSystemException ex2) { logger.error("Application exception overridden by rollback exception" , ex); ex2.initApplicationException(ex); throw ex2; } catch (RuntimeException | Error ex2) { logger.error("Application exception overridden by rollback exception" , ex); throw ex2; } } else { try { txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); } catch (TransactionSystemException ex2) { logger.error("Application exception overridden by commit exception" , ex); ex2.initApplicationException(ex); throw ex2; } catch (RuntimeException | Error ex2) { logger.error("Application exception overridden by commit exception" , ex); throw ex2; } } } }
至此,TransactionInterceptor
于我们而言已经没有任何秘密了。
后记 本篇我们一起分析了spring-tx
是如何通过spring-aop
的拦截器将普通方法增强为事务方法的,下篇就该说道说道PlatformTransactionManager
抽象下的事务管理细节啦,我们下篇再见~~