zoukankan      html  css  js  c++  java
  • 深入Spring:自定义事务管理

    转自:

    http://www.jianshu.com/p/5347a462b3a5

    前言

    上一篇文章讲了Spring的Aop,这里讲一下Spring的事务管理,Spring的事务管理是建立在Aop的基础上的,相比Aop,事务管理的实现耦合性比较小,自定义就比较简单了。

    自定义事务

    Spring的开启事务管理主要是通过@EnableTransactionManagement注解来实现的。
    查看源码就会发现,这个注解主要是注入了两个类InfrastructureAdvisorAutoProxyCreatorBeanFactoryTransactionAttributeSourceAdvisor,而且这两个类是通过其他的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的方法,并放到了事务中执行。同时在方法执行前后输出了方法的一些信息。


    customizeTransactional.jpg

    结语

    Spring的事务管理是建立在Aop之上的,借用了AdvisorInterceptor的很多方法。扩展一下,还可以通过自定义注解,对相应的方法进行代理。



    文/wcong(简书作者)
    原文链接:http://www.jianshu.com/p/5347a462b3a5
    著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
  • 相关阅读:
    视频上云解决方案EasyCVR支持接入海康SDK吗?
    视频上云网关EasyCVR程序数据库内数据会丢失吗?
    视频上云解决方案EasyCVR打包软件在linux下解压后台无法运行问题排查
    视频上云解决方案EasyCVR发布linux版本
    视频流媒体平台EasyNVR使用Vue.js开发报[Vue warn]错误问题解决方案
    监控现场无固定IP及公有云服务器如何通过手机查看视频直播?
    幼儿园EasyNVR能力层安防监控平台调用视频直播流报404错误解决方案
    海康NVR的RTSP视频流能否在EasyNVR流媒体平台中正常播放?
    视频云端流媒体平台EasyNVR存储的录像为什么呈现每小时一段录像?
    如何查看EasyNTS智能云组网硬件终端内的资源使用情况?
  • 原文地址:https://www.cnblogs.com/heyanan/p/6114946.html
Copyright © 2011-2022 走看看