深入Spring:自定義事務管理


Spring的開啟事務管理主要是通過@EnableTransactionManagement注解來實現的。
查看源碼就會發現,這個注解主要是注入了兩個類InfrastructureAdvisorAutoProxyCreator和BeanFactoryTransactionAttributeSourceAdvisor,而且這兩個類是通過其他的Configure類導入的。

  • InfrastructureAdvisorAutoProxyCreator繼承自AbstractAutoProxyCreator,自定義Aop里介紹過這個類,主要是讀取Advisor類,並對符合的bean進行二次代理。
  • BeanFactoryTransactionAttributeSourceAdvisor就是被掃描的Advisor類。這個類會掃面被Transactional注釋的類的方法,並提供TransactionInterceptor,來代理被注釋的方法。

完整的代碼參考Github,這里介紹一下幾個關鍵的類。

 

1、自定義的注解,簡便起見注解的屬性就不列出來了,跟Transactional的屬性一樣。

 

@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyTransactional {
    ....
}

 

2、DataSource和dao層,簡便起見,用的內存式數據庫h2,dao層用的是mybatis。

@Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean() {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource());
        return sqlSessionFactoryBean;
    }

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setBasePackage("org.wcong.test.spring.mybatis.mapper");
        return mapperScannerConfigurer;
    }

    @Bean
    public DataSource dataSource() {
        EmbeddedDatabaseBuilder embeddedDatabaseBuilder = new EmbeddedDatabaseBuilder();
        return embeddedDatabaseBuilder.setType(EmbeddedDatabaseType.H2).build();
    }

 

3、定義dao方法。

public interface DbTest {
    @Select("select count(*) from db_test")
    int count();
    @Insert("insert into db_test(id,date,content) values(#{id},now(),#{content})")
    @MyTransactional
    int add(TestModel testModel);
    @Insert("create table db_test(id int,date time,content varchar)")
    int createTable();
}

4、注入transactionManager。

@Bean(name = "transactionManager")
    public PlatformTransactionManager transactionManager() {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
        transactionManager.setDataSource(dataSource());
        return transactionManager;
    }

 

5、InfrastructureAdvisorAutoProxyCreator是直接使用Spring內置的類。

@Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public InfrastructureAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        return new InfrastructureAdvisorAutoProxyCreator();
    }

6、BeanFactoryTransactionAttributeSourceAdvisor需要掃描自定義的注解,並嵌入到方法執行的前后,就需要自己定義了。
  其中MySpringTransactionAnnotationParser繼承自Spring內置的SpringTransactionAnnotationParser類,重寫了掃描注解的方法。
    MyTransactionInterceptor則繼承了Spring內置的TransactionInterceptor重寫了invoke方法,在事務方法開始的前后輸出了部分信息。
    MyProxyTransactionManagementConfiguration則是參考的Spring的注入方式,組裝BeanFactoryTransactionAttributeSourceAdvisor並注入相關的Bean。

 

 

public static class MySpringTransactionAnnotationParser extends SpringTransactionAnnotationParser {
        @Override
        public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
            AnnotationAttributes attributes = AnnotatedElementUtils
                    .getMergedAnnotationAttributes(ae, MyTransactional.class);
            if (attributes != null) {
                return parseTransactionAnnotation(attributes);
            } else {
                return null;
            }
        }
        public TransactionAttribute parseTransactionAnnotation(MyTransactional ann) {
            return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));
        }
    }
    public static class MyTransactionInterceptor extends TransactionInterceptor {
        @Override
        public Object invoke(final MethodInvocation invocation) throws Throwable {
            System.out.println("transaction method :" +
                    invocation.getMethod().getDeclaringClass().getName() + "." + invocation.getMethod().getName());
            Object object = super.invoke(invocation);
            System.out.println(invocation.getMethod().getName() + " result :" + object);
            return object;
        }
    }
    @Configuration
    public static class MyProxyTransactionManagementConfiguration {
        protected PlatformTransactionManager txManager;
        @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(Ordered.LOWEST_PRECEDENCE);
            return advisor;
        }
        @Bean
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        public TransactionAttributeSource transactionAttributeSource() {
            return new AnnotationTransactionAttributeSource(new MySpringTransactionAnnotationParser());
        }
        @Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        public TransactionalEventListenerFactory transactionalEventListenerFactory() {
            return new TransactionalEventListenerFactory();
        }
        @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
        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
        public TransactionInterceptor transactionInterceptor() {
            TransactionInterceptor interceptor = new MyTransactionInterceptor();
            interceptor.setTransactionAttributeSource(transactionAttributeSource());
            if (this.txManager != null) {
                interceptor.setTransactionManager(this.txManager);
            }
            return interceptor;
        }
    }

觀察程序的日志就會發現在Spring加載了被MyTransactional的方法,並放到了事務中執行。同時在方法執行前后輸出了方法的一些信息。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM