@Transactional 注解元數據驅動的聲明式事務
基本原理是:
將對應的方法通過注解元數據,標注在業務方法或者所在的對象上,然后在業務執行期間,通過AOP攔截器反射讀取元數據信息,最終將根據讀取的業務信息構建事務管理支持。
不同的方法之間的事務傳播保證在同一個事務內,是通過統一的數據源來實現的,事務開始時將數據源綁定到ThreadLocal中,后續加入的事務從ThreadLocal獲取數據源來保證數據源的統一。
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Transactional { @AliasFor("transactionManager") String value() default ""; //事務管理器名稱 @AliasFor("value") String transactionManager() default ""; //事務傳播模式 Propagation propagation() default Propagation.REQUIRED; //事務隔離級別 Isolation isolation() default Isolation.DEFAULT; //超時時間 int timeout() default TransactionDefinition.TIMEOUT_DEFAULT; //是否是只讀事務 boolean readOnly() default false; //需要回滾的異常類 Class<? extends Throwable>[] rollbackFor() default {}; //需要回滾的異常類名稱 String[] rollbackForClassName() default {}; //排除回滾的異常類 Class<? extends Throwable>[] noRollbackFor() default {}; //排除回滾的異常類名稱 String[] noRollbackForClassName() default {}; }
這里通過SpringBoot代碼來分析實現過程,源碼中刪除了部分代碼,只保留了一些重要部分
// 事務自動配置類 注意類里面使用的@EnableTransactionManagement注解 org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration public class TransactionAutoConfiguration { @Configuration @ConditionalOnBean(PlatformTransactionManager.class) @ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class) public static class EnableTransactionManagementConfiguration { //注意這里使用的@EnableTransactionManagement注解 @Configuration @EnableTransactionManagement(proxyTargetClass = false) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false) public static class JdkDynamicAutoProxyConfiguration { } //注意這里使用的@EnableTransactionManagement注解 @Configuration @EnableTransactionManagement(proxyTargetClass = true) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true) public static class CglibAutoProxyConfiguration { } } }
這里只分析proxy模式
@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()); if (this.enableTx != null) { advisor.setOrder(this.enableTx.<Integer>getNumber("order")); } return advisor; } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionAttributeSource transactionAttributeSource() { return new AnnotationTransactionAttributeSource(); } //這里注入了TransactionInterceptor攔截器bean~~~~ @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; } }
TransactionInterceptor攔截器通過元數據獲取事務定義信息TransactionDefinition,根據Definition信息獲取PlatformTransactionManager(TM),tm接口抽象了事務的實現流程,默認的tm是DataSourceTransactionManager(通過DataSourceTransactionManagerAutoConfiguration初始化的),tm中的getTransaction根據事務的傳播方式,開啟、加入、掛起事務。
@Override public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException { Object transaction = doGetTransaction(); boolean debugEnabled = logger.isDebugEnabled(); if (definition == null) { // 使用默認的Definition definition = new DefaultTransactionDefinition(); } if (isExistingTransaction(transaction)) { //已經存在事務,進入單獨的方法處理 return handleExistingTransaction(definition, transaction, debugEnabled); } // 檢查timeout參數 if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) { throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout()); } // 當前必須存在事務,否則拋出異常 if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) { throw new IllegalTransactionStateException( "No existing transaction found for transaction marked with propagation 'mandatory'"); } else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) { //獲取當前的一些事務信息,用於當前事務執行完后恢復 SuspendedResourcesHolder suspendedResources = suspend(null); try { boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); //構造一個新事務的TransactionStatus(包含嵌套事務SavePoint的支持) DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, suspendedResources); //開啟新的事務 doBegin(transaction, definition); prepareSynchronization(status, definition); return status; } catch (RuntimeException | Error ex) { //異常,恢復掛起的事務信息 resume(null, suspendedResources); throw ex; } } else { //空的事務 boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS); return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null); } }
來看一個簡單實現版
1. 自定義注解 @MyTransaction
/** * @author yangxj * @see org.springframework.transaction.annotation.SpringTransactionAnnotationParser * @see org.springframework.transaction.interceptor.TransactionAttribute * @see org.springframework.transaction.TransactionDefinition */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface MyTransaction { String value() default ""; }
2. 自定義通知Advice
/** * @author yangxj * * @see org.springframework.transaction.PlatformTransactionManager * @see org.springframework.jdbc.datasource.DataSourceTransactionManager * @see org.springframework.transaction.interceptor.TransactionInterceptor */ @Slf4j public class MyTransactionInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { log.info("攔截到事務方法:{}", methodInvocation.getMethod().getName()); try { return methodInvocation.proceed(); // commit 提交事務 } catch (Exception e) { // rollback 回滾事務 } return null; } }
3. 織入
/** * @author yangxj * @see org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration * @see org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor */ @Configuration public class CommonConfiguration { @Bean public DefaultPointcutAdvisor myTransactionPointcutAdvisor() { DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(); // 切面 Aspect advisor.setPointcut(new AnnotationMatchingPointcut(null, MyTransaction.class)); // 方法級別注解匹配 切入點 pointcut advisor.setAdvice(new MyTransactionInterceptor()); // 通知 advice return advisor; } }
4. 演示
參考文章:
https://segmentfault.com/a/1190000022790265
https://www.cnblogs.com/yangxijun/p/14844490.html