一.背景
前面詳解了實現Spring事務的兩種方式的不同實現:編程式事務和聲明式事務,對於配置都使用到了xml配置,今天介紹Spring事務的註解開發,例如下面例子:
- 配置類:註冊數據源、JDBC模板、事務管理器
//包掃描,將包下的dao、service註冊到Spring容器中 @ComponentScan("com.hrh") //開啓基於註解的事務管理,跟@Transactional註解配套使用 @EnableTransactionManagement //表明TxConfig是配置類 @Configuration public class TxConfig { //註冊數據源 @Bean public DataSource dataSource() throws Exception { ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource(); comboPooledDataSource.setUser("xxx"); comboPooledDataSource.setPassword("xxx"); comboPooledDataSource.setJdbcUrl("jdbc:mysql://xxx:3306/xxx"); comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver"); return comboPooledDataSource; } //註冊jdbc模板 @Bean public JdbcTemplate jdbcTemplate() throws Exception { return new JdbcTemplate(dataSource()); } //註冊事務管理器來控制事務 @Bean public PlatformTransactionManager manager() throws Exception { return new DataSourceTransactionManager(dataSource()); } }
- 業務代碼:
@Repository public class UserDao { @Autowired private JdbcTemplate jdbcTemplate; public void insert(){ String sql ="insert into tab_person(name,age) values(?,?)"; String name = UUID.randomUUID().toString().substring(0, 5); jdbcTemplate.update(sql,name,19); } } @Service public class UserService{ @Autowired private UserDao userDao; //添加事務 @Transactional public void insert() { userDao.insert(); System.out.println("插入完成。"); int i = 10/0; } }
- 測試:從下面運行結果可以看出拋出了異常,在數據庫中查看數據發現沒有最新的數據插入,表明插入操作進行了回滾
public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class); UserService bean = context.getBean(UserService.class); bean.insert(); context.close(); } 運行結果: 插入完成。 Exception in thread "main" java.lang.ArithmeticException: / by zero at com.hrh.service.UserService.insert(UserService.java:20)
二. @EnableTransactionManagement註解源碼分析
1.流程
-
EnableTransactionManagement導入一個TransactionManagementConfigurationSelector組件
-
TransactionManagementConfigurationSelector默認導入兩個組件:AutoProxyRegistrar和ProxyTransactionManagementConfiguration
-
AutoProxyRegistrar(利用後置處理器包裝代理對象):註冊一個InfrastructureAdvisorAutoProxyCreator組件(自動代理創建器),利用後置處理器機制在對象創建之後包裝對象,返回一個代理對象(增強器),利用攔截器鏈執行方法
-
ProxyTransactionManagementConfiguration(註冊配置):給容器註冊各種組件,註冊了事務增強器
-
4.1)事務增強器要用事務註解的信息,AnnotationTransactionAttributeSource解析了註解上的各種屬性信息
4.2)同時用到TransactionInterceptor事務攔截器:保存了事務屬性信息、事務管理器
4.2.1)在目標方法執行時:執行攔截器鏈(即TransactionInterceptor)
4.2.2)TransactionInterceptor事務攔截器的作用:獲取事務相關的屬性,再獲取事務管理器進行事務的執行、回滾或提交操作;
2.源碼解析
- EnableTransactionManagement導入一個TransactionManagementConfigurationSelector組件
@Import({TransactionManagementConfigurationSelector.class}) public @interface EnableTransactionManagement { //默認爲false boolean proxyTargetClass() default false; //默認爲PROXY AdviceMode mode() default AdviceMode.PROXY; int order() default 2147483647; }
- TransactionManagementConfigurationSelector默認導入兩個組件:AutoProxyRegistrar和ProxyTransactionManagementConfiguration
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> { //AdviceMode值在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; } } }
- AutoProxyRegistrar(利用後置處理器包裝代理對象):註冊一個InfrastructureAdvisorAutoProxyCreator組件(自動代理創建器),利用後置處理器機制在對象創建之後包裝對象,返回一個代理對象(增強器),利用攔截器鏈執行方法
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar { @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"); Object proxyTargetClass = candidate.get("proxyTargetClass"); if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() && Boolean.class == proxyTargetClass.getClass()) { candidateFound = true; //註冊一個InfrastructureAdvisorAutoProxyCreator組件(自動代理創建器) if (mode == AdviceMode.PROXY) { AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); //proxyTargetClass在EnableTransactionManagement默認false if ((Boolean) proxyTargetClass) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); return; } } } } ..... } }
- AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry):自動代理創建器
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) { return registerAutoProxyCreatorIfNecessary(registry, null); } @Nullable public static BeanDefinition registerAutoProxyCreatorIfNecessary( BeanDefinitionRegistry registry, @Nullable Object source) { //給容器註冊InfrastructureAdvisorAutoProxyCreator(是一個後置處理器),利用後置處理器機制在對象創建之後包裝對象,返回一個代理對象(增強器),利用攔截器鏈執行方法 return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source); }
- AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry):自動代理創建器
- ProxyTransactionManagementConfiguration(註冊配置):給容器註冊各種組件,註冊了事務增強器
@Configuration public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration { //註冊事務增強器BeanFactoryTransactionAttributeSourceAdvisor @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() { BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor(); //設置事務屬性,從註解解析器獲取註解上的事務屬性值 advisor.setTransactionAttributeSource(transactionAttributeSource()); //設置了TransactionInterceptor事務攔截器 advisor.setAdvice(transactionInterceptor()); advisor.setOrder(this.enableTx.<Integer>getNumber("order")); return advisor; } //註冊事務屬性,解析註解中的各種屬性,比如propagation、isolation、timeout等 @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionAttributeSource transactionAttributeSource() { //註解解析器 return new AnnotationTransactionAttributeSource(); } //註冊了TransactionInterceptor事務攔截器:保存了事務屬性信息、事務管理器 @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; } }
- 註解解析器AnnotationTransactionAttributeSource
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) { this.publicMethodsOnly = publicMethodsOnly; this.annotationParsers = new LinkedHashSet<TransactionAnnotationParser>(4); //添加spring事務註解的解析器 this.annotationParsers.add(new SpringTransactionAnnotationParser()); if (jta12Present) { //添加jta事務註解的解析器 this.annotationParsers.add(new JtaTransactionAnnotationParser()); } if (ejb3Present) { //添加Ejb3事務註解的解析器 this.annotationParsers.add(new Ejb3TransactionAnnotationParser()); } } public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) { AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes( element, Transactional.class); if (attributes != null) { //解析註解 return parseTransactionAnnotation(attributes); } else { return null; } } //解析註解Transactional上的每個屬性 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<RollbackRuleAttribute>(); 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; }
- 事務攔截器TransactionInterceptor:是一個MethodInterceptor,方法攔截器(4個通知方法整合成了增強器,增強器整合成了MethodInterceptor。我們在容器中放置了一個代理對象,當要執行代理對象時,方法攔截器就執行了)
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(); } }); } protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation) throws Throwable { // If the transaction attribute is null, the method is non-transactional. //獲取事務屬性 final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass); //獲取事務管理器 final PlatformTransactionManager tm = determineTransactionManager(txAttr); //獲取執行的事務方法 final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { // Standard transaction demarcation with getTransaction and commit/rollback calls. //開啓事務 TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null; try { // 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) { // target invocation exception //事務異常會獲取事務管理器,利用事務管理器執行回滾操作 completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); } //如果正常,利用事務管理器提交事務 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; } } }
- 註解解析器AnnotationTransactionAttributeSource
- EnableTransactionManagement導入一個TransactionManagementConfigurationSelector組件