繁体   English   中英

如何在 Spring Boot 应用程序启动期间将 SynchronizationCallbacks 添加到 @TransactionalEventListener?

[英]How to add SynchronizationCallbacks to @TransactionalEventListener during spring boot application startup?

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

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

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

那么如何在 Spring Boot 应用程序启动期间将SynchronizationCallback添加到TransactionalApplicationListener中呢?

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

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

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

我对代码有类似的问题,如下所示

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM