spring-projects / spring-modulith

Modular applications with Spring Boot
https://spring.io/projects/spring-modulith
Apache License 2.0
774 stars 124 forks source link

Add `condition` to `@ApplicationModuleListener` #518

Closed maciejwalkowiak closed 6 months ago

maciejwalkowiak commented 6 months ago

@ApplicationModuleListener currently does not expose condition property from @TransactionalEventListener.

There are scenarios where listener is meant to handle event only if this event meets certain criteria. For example

public record BankTransferCreated(String id, Network network) { }

@Component
public class BankTransferListener {

    @ApplicationModuleListener
    void handle(BankTransferCreated event) {
        if (event.network() == Network.SEPA) {
            // do something
        }
    }
}

With code like above, there is an unnecessary insert & update into EVENT_PUBLICATION table - which ideally could be avoided. This can be achieved by not using @ApplicationModuleListener and falling back to @TransactionalEventListener:

@Async
@Transactional(propagation = Propagation.REQUIRES_NEW)
@TransactionalEventListener(condition = "#event.network() == T(com.example.demo.Network).SEPA")
void handle(BankTransferCreated event) {
    // do something
}

A quick win would be to just add condition property to @ApplicationModuleListener allowing following:

@ApplicationModuleListener(condition = "#event.network() == T(com.example.demo.Network).SEPA")
void handle(BankTransferCreated event) {
    // do something
}

As a side note, perhaps there could be a way to implement a method like boolean supports(T event) on the listener class that would be invoked for each published event, before event publication is registered. I think it would be more elegant than using SPEL.

odrotbohm commented 6 months ago

I went with the plain annotation attribute for now, as any kind of callback would require Spring's event handling adapted. Plus, a per-class condition method might not fit well with multiple listeners declared on a single class.