【问题标题】:How to add SynchronizationCallbacks to @TransactionalEventListener during spring boot application startup?如何在 Spring Boot 应用程序启动期间将 SynchronizationCallbacks 添加到 @TransactionalEventListener?
【发布时间】:2021-10-27 17:40:25
【问题描述】:

我有一个使用几个@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) 的spring boot 应用程序。我注意到当它们最终抛出异常时,spring boot 不会为它们做任何异常日志记录。

因此,我想为此类异常添加一些通用日志记录工具。我发现TransactionalApplicationListener.SynchronizationCallback是我需要实现的接口。然而,注册这些回调似乎很复杂。我没有在 spring 依赖项中找到任何可以实现此目的的 TransactionalApplicationListener#addCallback 调用。

尝试获取TransactionalApplicationListenerSynchronizationCallback 注入的列表,然后在@PostConstruct 中调用addCallback 并没有让我更进一步,因为即使应用程序确实成功使用,也始终没有注入侦听器其中。

那么如何在spring boot应用启动时将SynchronizationCallbacks添加到TransactionalApplicationListeners呢?

【问题讨论】:

    标签: java spring spring-boot


    【解决方案1】:

    我在下面的代码中遇到了类似的问题

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public class SomeListenerFacade {
        @TransactionalEventListener
        public void onSomething(SomeEvent event) {
            throw new RuntimeException("some cause");
        }
    }
    

    我遵循了您的解决方案。有效。在途中,我找到了一种至少在日志文件中看到该异常的替代方法

    # application.properties
    
    logging.level.org.springframework.transaction.support.TransactionSynchronizationUtils = DEBUG
    

    【讨论】:

      【解决方案2】:

      首先要注意的是TransactionalApplicationListeners 和所有ApplicationListener 一样在spring 上下文中不是bean。他们生活在它之外(见org.springframework.context.ConfigurableApplicationContext#addApplicationListener)。因此,对于应用程序上下文来说,注入它们是不可能的。

      在调试和查看 Spring 源代码时,发现这些侦听器是由 org.springframework.transaction.event.TransactionalEventListenerFactory 创建的。这就是我的解决方案所涉及的地方。我们用另一个知道SynchronizationCallbacks 的工厂来装饰那个工厂:

      public class SynchronizationCallbackAwareFactory implements EventListenerFactory, Ordered {
      
          private final TransactionalEventListenerFactory delegate;
          private final Provider<List<SynchronizationCallback>> synchronizationCallbacks;
          private final int order;
      
          public SynchronizationCallbackAwareFactory(TransactionalEventListenerFactory transactionalEventListenerFactory,
                                                     Provider<List<SynchronizationCallback>> synchronizationCallbacks,
                                                     int order) {
              this.delegate = transactionalEventListenerFactory;
              this.synchronizationCallbacks = synchronizationCallbacks;
              this.order = order;
          }
      
          @Override
          public boolean supportsMethod(Method method) {
              return delegate.supportsMethod(method);
          }
      
          @Override
          public ApplicationListener<?> createApplicationListener(String beanName, Class<?> type, Method method) {
              ApplicationListener<?> applicationListener = delegate.createApplicationListener(beanName, type, method);
              if (applicationListener instanceof TransactionalApplicationListener) {
                  TransactionalApplicationListener<?> listener = (TransactionalApplicationListener<?>) applicationListener;
                  Collection<SynchronizationCallback> callbacks = this.synchronizationCallbacks.get();
                  callbacks.forEach(listener::addCallback);
              }
              return applicationListener;
          }
      
          @Override
          public int getOrder() {
              return order;
          }
      }
      

      请注意,在我的例子中,我使用javax.inject.Provider 来尽可能最晚地检索回调。

      装饰器必须是Ordered,因为spring 将使用第一个支持它所遇到的方法的工厂。因此,此类实例的顺序必须具有更高的优先级,作为TransactionEventListenerFactory 的顺序值50

      【讨论】:

        猜你喜欢
        • 2019-04-11
        • 1970-01-01
        • 2021-10-13
        • 1970-01-01
        • 1970-01-01
        • 2015-10-14
        • 2019-08-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多