I have the need to register a separate application event listener for each request. The listener's purpose is to catch events coming in from other REST requests, while the listener's request is blocked awaiting all the required events to come in.
I have code such as this:
@Component
// @Scope(WebApplicationContext.SCOPE_REQUEST)
public static class WhistleEventListener implements ApplicationListener<WhistleEvent> {
volatile Consumer<WhistleEvent> handler;
@Override
public void onApplicationEvent(WhistleEvent we) {
final Consumer<WhistleEvent> h = handler;
if (h != null) h.accept(we);
}
}
@Autowired WhistleEventListener whistleEventListener;
This code receives events, but as soon as I uncomment the @Scope
annotation, it stops receiving events.
Are request-scoped application event listeners supported, are they supposed to work? If so, can I do something to make my listener work?
I suspect you have a misunderstanding of the application event dispatching mechanics: the event is dispatched against bean definitions, not bean instances, and each bean definition is resolved into an instance at the moment, and in the context, of event publication. That means that your event will be dispatched only to the request-scoped bean belonging to the request inside which the event is published, but you want the listeners of all current requests to be notified.
More generally, the purpose of a scope is to isolate scope instances, which contain separate bean instances. If you do not want isolation, you should use a scope that does not have separate instances, for instance the application scope.
That is, to dispatch events to other scope instances, you'd have to do the dispatching yourself, for instance like:
@Component
public class WhistleEventMediator implements ApplicationListener<WhistleEvent> {
// TODO: make thread safe
final Set<Consumer<WhistleEvent>> consumers;
void subscribe(Consumer<WhistleEvent> c) { ... }
void unsubscribe(Consumer<WhistleEvent> c) { ... }
@Override public void onApplicationEvent(WhistleEvent we) {
// delegate to subscribed consumers
}
}
@Component
@Scope(WebApplicationContext.SCOPE_REQUEST)
public class WhateverBean implements Consumer<WhistleEvent> {
@Inject
WhistleEventMediator mediator;
@PostConstruct
void init() {
mediator.subscribe(this);
}
@PreDestroy
void destroy() {
mediator.unsubscribe(this);
}
// handle whistle event
}
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