我正在从事Spring Boot应用程序的事件驱动设计。
代码包含以下文件:
春季启动:ApplicationEvent文件,即MyBusinessEvent。{java
@Data
@AllArgsConstructor
public class MyBusinessEvent {
private String data;
}
事件发布者文件: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);
}
}
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
时。例如:
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
,它根本不起作用。
应用程序没有遇到任何异常(即使在运行时也没有异常),但是没有按预期的记录。
是否缺少任何配置?
答案 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云流的好处在于,它为您提供了一些与所使用的消息代理无关的抽象概念。
您可以在所有支持的活页夹之间切换,而无需更改应用程序中的任何内容