【深入学习Spring】8——Spring事务管理源码分析
在Spring AOP源码分析中我们分析了Spring AOP的工作原理,而Spring的事务管理是基于Spring AOP的。所以,搞懂了Spring AOP的工作流程后再来研究Spring的事务管理会更轻车熟路。
一、事务程序
先以一段事务管理的程序来引出后文。首先,在mysql中默认的test库中创建一张tbl_user表。
接下来写一段程序,用上事务管理。
下面是pom文件
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.26.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.3.26.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.3.26.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.26.RELEASE</version> </dependency> <!--mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.0.4</version> <!--<scope>runtime</scope>--> </dependency> </dependencies>
然后是主程序
@EnableTransactionManagement @ComponentScan("com.lp.test.tx") @Configuration public class TxConfig { @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setUsername("root"); dataSource.setPassword("root"); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://localhost:3306/test"); return dataSource; } @Bean public JdbcTemplate jdbcTemplate() { return new JdbcTemplate(dataSource()); } @Bean public PlatformTransactionManager transactionManager() { return new DataSourceTransactionManager(dataSource()); } } @Service public class UserService { @Autowired private UserDao userDao; @Transactional public void insertUser() { userDao.insert(); System.out.println("insert Success!"); //int i = 1 / 0; } } @Repository public class UserDao { @Autowired private JdbcTemplate jdbcTemplate; public void insert() { String sql = "INSERT INTO tbl_user(name,age) VALUES(?,?)"; String username = UUID.randomUUID().toString().substring(0, 5); jdbcTemplate.update(sql, username, 18); } } public class TxMain { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class); UserService userService = (UserService) context.getBean("userService"); userService.insertUser(); } }
二、源码分析
下面开始源码跟踪和分析。要使用事务功能,首先需要在配置类上加上@EnableTransactionManagement注解,该注解是整个事务管理的开关,所以我们先从该注解入手来进行研究。首先查看一下该注解的声明
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(TransactionManagementConfigurationSelector.class) public @interface EnableTransactionManagement { boolean proxyTargetClass() default false; AdviceMode mode() default AdviceMode.PROXY;//默认为PROXY int order() default Ordered.LOWEST_PRECEDENCE; }
发现该注解又通过@Import注解导入了一个TransactionManagementConfigurationSelector选择器组件,我们再进入该组件类中
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[] { TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME}; default: return null; } } }
TransactionManagementConfigurationSelector继承了AdviceModeImportSelector,最终实现的是ImportSelector接口。在Spring容器中注册组件的几种方式总结中我们已经提到过ImportSelector搭配@Import可以用来向容器中导入组件。看看其中的selectImports方法,adviceMode有两种模式:PROXY和ASPECTJ。我们再回头看看@EnableTransactionManagement注解的声明,其中的AdviceMode属性默认值为PROXY,所以这里我们直接关注PROXY模式。也就是说默认的PROXY模式下,TransactionManagementConfigurationSelector又会导入两个组件:AutoProxyRegistrar和ProxyTransactionManagementConfiguration。
这里直接或间接的导入了好几个组件,这里我画图来展示。
那我们就来开始研究这两个组件。
1.AutoProxyRegistrar
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar { private final Log logger = LogFactory.getLog(getClass()); @Override 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");//获取注解属性中的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) {//PROXY模式 AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);//【注册组件】 if ((Boolean) proxyTargetClass) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); return; } } } } if (!candidateFound && logger.isWarnEnabled()) { 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)); } } }
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
-->registerAutoProxyCreatorIfNecessary()
-->registerOrEscalateApcAsRequired()
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) { return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);//【InfrastructureAdvisorAutoProxyCreator】 } private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, 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; } //注册组件,类型为方法参数中传入的InfrastructureAdvisorAutoProxyCreator 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; }
调用registerOrEscalateApcAsRequired()时,会注册一个组件InfrastructureAdvisorAutoProxyCreator,那我们就来看看该类。下面是该类继承体系。现在再回头看看Spring源码系列7 - AOP中介绍的AnnotationAwareAspectJAutoProxyCreator类继承体系图,发现它们是从共同父类AbstractAutoProxyCreator一路继承下来。所以,我将AOP部分的AnnotationAwareAspectJAutoProxyCreator也一并画了进来,便于参照理解。
既然有了参照,我们理解起来应该就很容易了。InfrastructureAdvisorAutoProxyCreator自然也是一个后置处理器,其上层父类AbstractAutoProxyCreator实现了后置处理器中的回调方法postProcessAfterInitialization,该方法在执行时会调用wrapIfNecessary()对bean进行包装,这里的包装就是对Bean创建代理对象(增强)。
2.ProxyTransactionManagementConfiguration
我们再来看另一个组件ProxyTransactionManagementConfiguration,它是一个配置类,通过该配置类会注册一个事务增强器BeanFactoryTransactionAttributeSourceAdvisor,而该事务增强器需要一个事务属性源和一个事务拦截器,所以配置类中也同时注册一个事务属性源和一个事务拦截器。
@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();//注解事务属性源, } //事务拦截器 @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环境下也就是添加了一个SpringTransactionAnnotationParser,该解析器就是用来解析事务属性的,也就是方法上的@Transaction注解中的属性。
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) { this.publicMethodsOnly = publicMethodsOnly; this.annotationParsers = new LinkedHashSet<TransactionAnnotationParser>(4); this.annotationParsers.add(new SpringTransactionAnnotationParser());//Spring事务注解解析器 if (jta12Present) { this.annotationParsers.add(new JtaTransactionAnnotationParser());//Jta } if (ejb3Present) { this.annotationParsers.add(new Ejb3TransactionAnnotationParser());Ejb } }
另外,通过声明就知道事务拦截器是一个方法拦截器,其作用就是在目标方法调用时会进行拦截,从而执行增强操作。在下面目标方法调用部分会进行讲解。
3.目标方法调用
当我们的程序中insertUser()方法被调用时,拦截器链就要大显身手了。事务管理本质上也是基于AOP的,前面我们写的程序使用的是Cglib动态代理方式,在Spring源码系列7 - AOP源码分析 中我们已经分析过Cglib代理方式下会使用拦截器DynamicAdvisedInterceptor(它是CglibAopproxy类的内部类)拦截目标方法的调用。
CglibAopProxy.DynamicAdvisedInterceptor.invoke()
-->ReflectiveMethodInvocation.proceed() //执行拦截器链
之后的流程就基本上是一样的了。执行拦截器链时,拦截器链中只有一个事务拦截器。
我们来看看事务拦截器做了些什么操作。
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable { …… @Override 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... return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() { @Override public Object proceedWithInvocation() throws Throwable { return invocation.proceed(); } }); } …… }
TransactionInterceptor#invoke
-->TransactionAspectSupport#invokeWithinTransaction
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation) throws Throwable { //1.获取事务的属性 // If the transaction attribute is null, the method is non-transactional. final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass); //2.获取平台事务管理器 final PlatformTransactionManager tm = determineTransactionManager(txAttr); final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { //3.开启事务 // Standard transaction demarcation with getTransaction and commit/rollback calls. TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal; try { //4.执行方法 // 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) { //5.1如果发生异常,进行回滚 // target invocation exception completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); } //5.2.如果正常执行,提交事务 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, new TransactionCallback<Object>() { @Override public Object doInTransaction(TransactionStatus 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. 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 { 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; } } } protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) { …… try { //拿到事务管理器,执行回滚 txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); } …… } protected void commitTransactionAfterReturning(TransactionInfo txInfo) { …… //拿到事务管理器,提交事务 txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); …… }
整个过程我们应该非常熟悉,获取了事务属性和平台事务管理器后,接下来要执行方法了,执行方法前如果有必要的话(开启了事务),则先开启事务。然后执行方法,如果方法正常执行,则提交事务。如果方法执行发生异常,则回滚事务。
总结
我们通过@EnableTransactionManagement注解打开事务管理的开关,该注解又通过@Import向容器中导入了一个TransactionManagementConfigurationSelector选择器组件,该选择器组件又会向容器中导入AutoProxyRegistrar和ProxyTransactionManagementConfiguration这两个组件。
- AutoProxyRegistrar:这个组件又会向容器中注册另外一个组件InfrastructureAdvisorAutoProxyCreator,该组件是一个后置处理器,作用是在Bean创建完并初始化后进行包装操作,具体上就是对Bean创建代理对象(增强)。[回忆一下refresh中有一个注册后置处理器的步骤]
- ProxyTransactionManagementConfiguration:这是一个配置类,通过该配置类会注册一个事务增强器BeanFactoryTransactionAttributeSourceAdvisor,一个事务属性源AnnotationTransactionAttributeSource和一个事务拦截器TransactionInterceptor 。
代理对象的方法在执行时,会走拦截器链,拦截器链中的事务拦截器会拦截到目标方法,拦截后就执行事务操作:(如有需要)开启事务,执行目标方法。正常执行完则提交事务,执行异常则回滚事务。