简体   繁体   English

请求范围的ApplicationEventListener无法接收事件

[英]Request-scoped ApplicationEventListener fails to receive events

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. 侦听器的目的是捕获来自其他REST请求的事件,同时阻止侦听器的请求等待所有必需的事件进入。

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. 此代码接收事件,但是一旦取消注释@Scope注释,它就会停止接收事件。

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. 我怀疑你对应用程序事件调度机制有一个误解:事件是针对bean 定义而不是bean 实例调度的,并且每个bean定义现在被解析为一个实例,并且在上下文中被解析为事件发布。 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. 这意味着您的事件将仅发送到属于发布事件的请求的请求范围的bean,但您希望通知所有当前请求的侦听器。

More generally, the purpose of a scope is to isolate scope instances, which contain separate bean instances. 更一般地,范围的目的是隔离包含单独的bean实例的范围实例。 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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM