I need to asynchronously react to the @EventListener
, therefore I've created something like this.
@Service
public class AsyncHandler {
private CompletableFuture<My> future;
@Async
public CompletableFuture<My> getMy() {
future = new CompletableFuture<>();
return future;
}
@EventListener
public void processEvent(MyEvent event) {
future.complete(event.my());
}
}
The problem here is that AsyncHandler
is now stateful. Which is wrong.
And I don't want to use database, so is there any other way to make the bean stateless while using @EventListener
?
CodePudding user response:
You are right, your singleton has state, which is "not good".
One (possible) solution:
- make the/refactor "statfeul part" to a "prototype" (request, session) scope bean.
- make your "singleton" abstract!
- inject the "stateful part" via "method injection" (we cannot "auto wire" lower(shorter-living) scope beans to higher ones...)
As code (example):
- State holder:
public class MyStateHolder { // State: private CompletableFuture<My> future; @Async // ? public CompletableFuture<My> getMy() { future = new CompletableFuture<>(); return future; } }
- Abstract, (no
@Service
..yet, no state!):public abstract class AsyncHandler { @EventListener public void processEvent(MyEvent event) { // !! delegate().getMy().complete(event.my()); } // and now only (abstract!): public abstract MyStateHolder delegate(); }
- Wiring :
@Configuration class MyConfig { @Bean @Scope("prototype") // ! public MyStateHolder stateful() { return new MyStateHolder(); } @Bean // singleton/service: public AsyncHandler asyncHandler() { return new AsyncHandler() { // ! @Override // ! public MyStateHolder delegate() { return stateful();// !;) } }; } }
refs: (most of) https://docs.spring.io/spring-framework/docs/current/reference/html/core.html