I'm working in an event-driven design of spring boot application.
The code consists of following files:
Spring boot: ApplicationEvent File i.e MyBusinessEvent.{java
@Data
@AllArgsConstructor
public class MyBusinessEvent {
private String data;
}
Event Publisher File: 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);
}
}
The point is when Listener file consists @EventListener
then the app works as expected but when I do @TransactionEventListener
. For example:
TransactionalEventListener : MyBusinessEventListener.java
@Slf4j
@Component
public class MyBusinessEventListener {
@TransactionalEventListener
public void handleEvent(MyBusinessEvent myBusinessEvent) {
log.info("[MyBusinessEventListener] New event received with following data: {}", myBusinessEvent);
}
}
with @TransactionalEventListener
, it doesn't work at all.
The application doesn't through any exception (not even at runtime) but there is no logging as expected.
Is any configuration missing?
Add @Transactional
annotation to MyBusinessService.save
should fix this issue.
As per java documentation, @TransactionalEventListener
work within @Transactional
boundary.
Here what documentation says,
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.
If you don't want your service method in transaction boundary then use @TransactionalEventListener(fallbackExecution = true)
EDIT: There are three possible solutions to the above problem.
i. Mark class
as @Transactional
to be considered as 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. Make the specific method of service as @Transactional
@Override
@Transactional
public void save() {
String data = "Testing event data";
MyBusinessEvent event = new MyBusinessEvent(data);
applicationEventPublisher.publishEvent(event);
}
iii. If you don't want your service method in transaction boundary then use
@Slf4j
@Component
public class MyBusinessEventListener {
@TransactionalEventListener(fallbackExecution = true)
public void handleEvent(MyBusinessEvent myBusinessEvent) {
log.info("[MyBusinessEventListener] New event received with following data: {}", myBusinessEvent);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With