在本篇文章中,将会介绍如何在spring中进行事务管理,之后对其内部原理进行分析。主要涉及
我们可以在配置类上标记注解@EnableTransactionManagement,这样就可以设置spring应用开启事务管理。 之后我们可以在需要开启事务的方法上标注@Transactional,spring将利用AOP框架,生成代理类,为方法配置事务增强。下面看一个具体的例子
@Configuration @EnableTransactionManagement // 我们这一节的重点研究对象 public class MybatisConfig { // 各种其他配置,如数据源配置、mybatis的SqlSessionFactory等 } 复制代码
// 接口类 public interface CountryService { int createCountry(Country country); } // 实现,我们故意让其抛出异常 public class CountryServiceImpl implements CountryService { // ... 注入countryMapper @Override @Transactional public int createCountry(Country country) { // 使用mybatis mapper来操作数据库 int result = countryMapper.insert(country); int i = 1 / 0; // 抛出RuntimeException,事务回滚 return result; } } 复制代码
public class ContextTest { public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext(MybatisConfig.class); CountryService countryService = context.getBean(CountryService.class); Country country = new Country(); country.setCountryName("中国"); country.setCountryCode("CN"); // 由于我们在countryService中,抛出了异常。因此这里的数据将发生回滚,不会写入到数据库中 countryService.createCountry(country); } } 复制代码
从以上的demo,我们可以看出来。利用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; } 复制代码
从注解的代码中,可以看出在其内部通过@Import注解导入了TransactionManagementConfigurationSelector类
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> { /** * {@inheritDoc} * @return {@link ProxyTransactionManagementConfiguration} or * {@code AspectJTransactionManagementConfiguration} for {@code PROXY} and * {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()}, respectively */ @Override protected String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}; case ASPECTJ: return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME}; default: return null; } } } 复制代码
TransactionManagementConfigurationSelector实现了接口ImportSelector
由于整个解析配置的流程过于复杂,代码量繁多。这里就不一一列出具体代码了。下面提供一个主流程的时序图,有兴趣的看官可以跟着流程图去浏览一下相关源码。
在spring解析配置的过程中,将调用方法AutoProxyRegistrar#registerBeanDefinitions,最终向容器中注册了自动代理生成器InfrastructureAdvisorAutoProxyCreator
@Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean candidateFound = false; Set<String> annoTypes = importingClassMetadata.getAnnotationTypes(); for (String annoType : annoTypes) { AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType); 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) { // 该方法内部将注册一个自动生成代理类(InfrastructureAdvisorAutoProxyCreator) AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); if ((Boolean) proxyTargetClass) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); return; } } } } if (!candidateFound) { String name = getClass().getSimpleName(); logger.warn(String.format("%s was imported but no annotations were found " + "having both 'mode' and 'proxyTargetClass' attributes of type " + "AdviceMode and boolean respectively. This means that auto proxy " + "creator registration and configuration may not have occurred as " + "intended, and components may not be proxied as expected. Check to " + "ensure that %s has been @Import'ed on the same class where these " + "annotations are declared; otherwise remove the import of %s " + "altogether.", name, name, name)); } } 复制代码
而且,在解析配置的过程中,将处理Import进来的配置类ProxyTransactionManagementConfiguration。 其内部存在三个用@Bean注解标注的方法如下,将向容器注册其各自返回的bean。
@Configuration public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration { // 注册一个切面 @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() { BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor(); advisor.setTransactionAttributeSource(transactionAttributeSource()); advisor.setAdvice(transactionInterceptor()); advisor.setOrder(this.enableTx.<Integer>getNumber("order")); return advisor; } // @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionAttributeSource transactionAttributeSource() { return new AnnotationTransactionAttributeSource(); } // 切面逻辑(Advice) @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionInterceptor transactionInterceptor() { TransactionInterceptor interceptor = new TransactionInterceptor(); interceptor.setTransactionAttributeSource(transactionAttributeSource()); if (this.txManager != null) { interceptor.setTransactionManager(this.txManager); } return interceptor; } } 复制代码
spring通过AOP框架在容器启动时,自动发现需要事务增强的类或方法(即标注了@Transactional的类或方法),为这些方法嵌入事务切面(即BeanFactoryTransactionAttributeSourceAdvisor)生成代理类,之后我们从容器获取到的对应的bean就是进行事务增强后的代理类。大致的步骤包括:
大致的流程图如下所示
public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator { // postProcessAfterInitialization接口在其父类中实现 } 复制代码
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware { @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (!this.earlyProxyReferences.contains(cacheKey)) { // 代理生成逻辑 return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (beanName != null && this.targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // Create proxy if we have advice. // 在这个方法内部将调用TransactionAttributeSourcePointcut#match方法进行匹配,如果匹配成功那么会返回BeanFactoryTransactionAttributeSourceAdvisor实例 // 这个方法完成了以下几个工作 // 1. 从beanfactory中获取所有注册到beanfactory中的Advisor,将Advisor进行实例化 // 2. 调用Advisor中的Pointcut的matches方法,进行匹配。匹配成功则返回当前Advisor // 3. 在事务管理的框架中,匹配细节由TransactionAttributeSourcePointcut#matches方法负责,其内部会调用AnnotationTransactionAttributeSource#getTransactionAttribute方法解析@Transactional注解 // 4. 对于局部事务来说,解析@Transactional的解析将委托给SpringTransactionAnnotationParser Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors != DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); // 在这个方法内部将使用ProxyFactory来生成代理 Object proxy = createProxy( bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } } 复制代码
这里先看一下BeanFactoryTransactionAttributeSourceAdvisor的类图,大概了解下这个类是在整个事务管理体系中是属于什么角色。
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor { private TransactionAttributeSource transactionAttributeSource; // 切面内的Pointcut,用于在生成代理的过程中进行匹配方法 private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() { @Override protected TransactionAttributeSource getTransactionAttributeSource() { return transactionAttributeSource; } }; /** * Set the transaction attribute source which is used to find transaction * attributes. This should usually be identical to the source reference * set on the transaction interceptor itself. * @see TransactionInterceptor#setTransactionAttributeSource */ public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) { this.transactionAttributeSource = transactionAttributeSource; } /** * Set the {@link ClassFilter} to use for this pointcut. * Default is {@link ClassFilter#TRUE}. */ public void setClassFilter(ClassFilter classFilter) { this.pointcut.setClassFilter(classFilter); } @Override public Pointcut getPointcut() { return this.pointcut; } } 复制代码
可以看出,这个类间接实现了接口PointcutAdvisor,这是一个切面类(即组合了Pointcut、Advice)。其内部定义的Pointcut为抽象类TransactionAttributeSourcePointcut的匿名实现类。关于AOP的这些概念,可以参考:spring-AOP原理分析一和spring-AOP原理分析二,这里不再赘述。
这个类间接实现了两个接口:Pointcut、MethodMatcher。在事务管理中作为AOP的pointcut、methodMatcher两个角色。用于匹配方法是否需要进行事务增强
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { // 通过AnnotationTransactionAttributeSource来获取 @Override public boolean matches(Method method, Class<?> targetClass) { if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) { return false; } // 获取到的tas为AnnotationTransactionAttributeSource实例, // 在ProxyTransactionManagementConfiguration中注册而来 TransactionAttributeSource tas = getTransactionAttributeSource(); return (tas == null || tas.getTransactionAttribute(method, targetClass) != null); } @Override public boolean equals(Object other) { if (this == other) { return true; } if (!(other instanceof TransactionAttributeSourcePointcut)) { return false; } TransactionAttributeSourcePointcut otherPc = (TransactionAttributeSourcePointcut) other; return ObjectUtils.nullSafeEquals(getTransactionAttributeSource(), otherPc.getTransactionAttributeSource()); } @Override public int hashCode() { return TransactionAttributeSourcePointcut.class.hashCode(); } @Override public String toString() { return getClass().getName() + ": " + getTransactionAttributeSource(); } /** * Obtain the underlying TransactionAttributeSource (may be {@code null}). * To be implemented by subclasses. */ protected abstract TransactionAttributeSource getTransactionAttributeSource(); } 复制代码
在TransactionAttributeSourcePointcut#matches(Method method, Class targetClass)方法中,将调用AnnotationTransactionAttributeSource#getTransactionAttribute(Method method, Class targetClass)方法,用于获取TransactionAttribute,即配置到@Transactional的属性值。实际的获取动作代理给了父类AbstractFallbackTransactionAttributeSource
public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource implements Serializable { // ... 省略code } public abstract class AbstractFallbackTransactionAttributeSource implements TransactionAttributeSource { @Override public TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass) { if (method.getDeclaringClass() == Object.class) { return null; } // First, see if we have a cached value. Object cacheKey = getCacheKey(method, targetClass); Object 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 (TransactionAttribute) 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.isDebugEnabled()) { logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr); } this.attributeCache.put(cacheKey, txAttr); } return txAttr; } } // 解析@Transaction注解的属性值 protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) { // Don't allow no-public methods as required. // 1. 只有public方法可以切入事务管理 if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null; } // Ignore CGLIB subclasses - introspect the actual user class. Class<?> userClass = ClassUtils.getUserClass(targetClass); // The method may be on an interface, but we need attributes from the target class. // If the target class is null, the method will be unchanged. Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass); // If we are dealing with method with generic parameters, find the original method. specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod); // First try is the method in the target class. TransactionAttribute txAttr = findTransactionAttribute(specificMethod); if (txAttr != null) { return txAttr; } // Second try is the transaction attribute on the target class. txAttr = findTransactionAttribute(specificMethod.getDeclaringClass()); if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { return txAttr; } if (specificMethod != method) { // Fallback is to look at the original method. txAttr = findTransactionAttribute(method); if (txAttr != null) { return txAttr; } // Last fallback is the class of the original method. txAttr = findTransactionAttribute(method.getDeclaringClass()); if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { return txAttr; } } return null; } @Override protected TransactionAttribute findTransactionAttribute(Method method) { return determineTransactionAttribute(method); } protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) { if (ae.getAnnotations().length > 0) { // TransactionAnnotationParser的实现类有Ejb3TransactionAnnotationParser、JtaTransactionAnnotationParser、SpringTransactionAnnotationParser // 对于局部失误,我们使用SpringTransactionAnnotationParser来进行解析 for (TransactionAnnotationParser annotationParser : this.annotationParsers) { TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae); if (attr != null) { return attr; } } } return null; } } public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable { @Override public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) { AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class); if (attributes != null) { return parseTransactionAnnotation(attributes); } else { return null; } } public TransactionAttribute parseTransactionAnnotation(Transactional ann) { return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false)); } 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")); ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRuleAttribute>(); Class<?>[] rbf = attributes.getClassArray("rollbackFor"); for (Class<?> rbRule : rbf) { RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule); rollBackRules.add(rule); } String[] rbfc = attributes.getStringArray("rollbackForClassName"); for (String rbRule : rbfc) { RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule); rollBackRules.add(rule); } Class<?>[] nrbf = attributes.getClassArray("noRollbackFor"); for (Class<?> rbRule : nrbf) { NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule); rollBackRules.add(rule); } String[] nrbfc = attributes.getStringArray("noRollbackForClassName"); for (String rbRule : nrbfc) { NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule); rollBackRules.add(rule); } rbta.getRollbackRules().addAll(rollBackRules); return rbta; } @Override public boolean equals(Object other) { return (this == other || other instanceof SpringTransactionAnnotationParser); } @Override public int hashCode() { return SpringTransactionAnnotationParser.class.hashCode(); } } 复制代码
以上我们从一个demo入手,了解了如何使用spring来管理事务;之后我们从配置的注解@EnableTransactionManagement切入到spring事务框架的内部原理。期间涉及了几个主要的类:
鉴于篇幅过长了,O(≧口≦)O。。。下一节我们再对事务管理的逻辑进行剖析,即对TransactionInterceptor进行分析