@TransactionalEventListener不起作用,因为@EventListener就像在同一上下文中的超级按钮一样

时间:2018-06-29 08:55:35

标签: java spring-boot event-listener

我正在从事Spring Boot应用程序的事件驱动设计。

代码包含以下文件:

  1. 春季启动:ApplicationEvent文件,即MyBusinessEvent。{java

    @Data
    @AllArgsConstructor
    public class MyBusinessEvent {
    
       private String data;
    
    }
    
  2. 事件发布者文件:MyBusinessService.java

    @Slf4j
    @Service
    public class MyBusinessService {
    
        private final ApplicationEventPublisher applicationEventPublisher;
    
        @Autowired
        public MyBusinessService(
                ApplicationEventPublisher applicationEventPublisher) {
    
            this.applicationEventPublisher = applicationEventPublisher;
        }
    
        @Override
        public void save() {
            String data = "Testing event data";
            MyBusinessEvent event = new MyBusinessEvent(data);
            applicationEventPublisher.publishEvent(event);
        }
    }
    
  3. EventListener:MyBusinessEventListener.java

    @Slf4j
    @Component
    public class MyBusinessEventListener {
    
        @EventListener
        public void handleEvent(MyBusinessEvent myBusinessEvent) {
            log.info("[MyBusinessEventListener] New event received with following data: {}", myBusinessEvent);
        }
    }
    

重点是,当侦听器文件包含@EventListener时,应用程序将按预期运行,但是当我执行@TransactionEventListener时。例如:

  1. TransactionalEventListener:MyBusinessEventListener.java

    @Slf4j
    @Component
    public class MyBusinessEventListener {
    
        @TransactionalEventListener
        public void handleEvent(MyBusinessEvent myBusinessEvent) {
            log.info("[MyBusinessEventListener] New event received with following data: {}", myBusinessEvent);
        }
    }
    

对于@TransactionalEventListener,它根本不起作用。

应用程序没有遇到任何异常(即使在运行时也没有异常),但是没有按预期的记录。

是否缺少任何配置?

2 个答案:

答案 0 :(得分:2)

@Transactional添加MyBusinessService.save注释应该可以解决此问题。

根据Java文档,@TransactionalEventListener@Transactional范围内工作。

这是文档所说的

If the event is not published within the boundaries of a managed transaction, the
 * event is discarded unless the {@link #fallbackExecution} flag is explicitly set.

如果您不想在事务边界中使用服务方法,请使用@TransactionalEventListener(fallbackExecution = true)

编辑: 解决上述问题的方法有三种。

i。将class标记为@Transactional视为可交易

@Transactional
@Service
public class MyBusinessService {

    private final ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    public MyBusinessService(
            ApplicationEventPublisher applicationEventPublisher) {

        this.applicationEventPublisher = applicationEventPublisher;
    }

    @Override
    public void save() {
        String data = "Testing event data";
        MyBusinessEvent event = new MyBusinessEvent(data);
        applicationEventPublisher.publishEvent(event);
    }
 }

ii。将特定的服务方法设置为@Transactional

@Override
@Transactional
public void save() {
    String data = "Testing event data";
    MyBusinessEvent event = new MyBusinessEvent(data);
    applicationEventPublisher.publishEvent(event);
}

iii。如果您不希望在事务边界中使用服务方法,请使用

@Slf4j
@Component
public class MyBusinessEventListener {

    @TransactionalEventListener(fallbackExecution = true)
    public void handleEvent(MyBusinessEvent myBusinessEvent) {
        log.info("[MyBusinessEventListener] New event received with following data: {}", myBusinessEvent);
    }
}

答案 1 :(得分:1)

您的ApplicationEventPublisher类应如下所示:@ Slf4j @Service public

class MyBusinessService {

    private final ApplicationEventPublisher applicationEventPublisher;

    @Autowired
    public MyBusinessService(
            ApplicationEventPublisher applicationEventPublisher) {

        this.applicationEventPublisher = applicationEventPublisher;
    }

    @Override
    @Transactional
    public void save() {
        String data = "Testing event data";
        MyBusinessEvent event = new MyBusinessEvent(data);
        applicationEventPublisher.publishEvent(event);
    }
 }

但是请注意,这种功能的可交易性特别是指数据库的可交易性。

如果您希望在事件监听器发生异常的情况下,如果事件监听器消耗的消息再次可用,则此功能不受支持,在这种情况下,您应该考虑像RabbitMQ这样的消息代理,它支持事务性消息传递

如果您尚未在应用程序中使用Spring Cloud,我建议您使用Spring Cloud Stream,它可以帮助您创建事件驱动的应用程序。

Spring云流的好处在于,它为您提供了一些与所使用的消息代理无关的抽象概念。

您可以在所有支持的活页夹之间切换,而无需更改应用程序中的任何内容

相关问题