我对此感到困惑。我创建了三个应该监听事件的bean实例,但只有其中一个捕获事件。为什么?请参阅下面的代码和输出。 PS。春天来了。
事件处理程序类
package customevents.di;
import org.springframework.context.ApplicationListener;
public class CustomEventHandler implements ApplicationListener<CustomEvent> {
private static int ID = 0;
public CustomEventHandler() {
ID++;
System.out.println("Constructor called CustomEventHandler " + ID);
}
public void onApplicationEvent(CustomEvent event) {
System.out.println(event.toString() + " " + ID); // Prints My Custom event and ID
}
}
出版商
package customevents.di;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
public class CustomEventPublisher implements ApplicationEventPublisherAware {
private ApplicationEventPublisher publisher;
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public void publish() {
CustomEvent ce = new CustomEvent(this);
publisher.publishEvent(ce);
}
}
用法
public static void main(String[] args) {
ConfigurableApplicationContext context =
new ClassPathXmlApplicationContext("Beans.xml");
CustomEventPublisher cvp =
(CustomEventPublisher) context.getBean("customEventPublisher");
// Scope of these beans is prototype
CustomEventHandler ce = (CustomEventHandler) context.getBean("customEventHandler");
CustomEventHandler ce1 = (CustomEventHandler) context.getBean("customEventHandler");
CustomEventHandler ce2 = (CustomEventHandler) context.getBean("customEventHandler");
cvp.publish();
}
输出
Constructor called CustomEventHandler 1
Constructor called CustomEventHandler 2
Constructor called CustomEventHandler 3
Constructor called CustomEventHandler 4
My Custom Event 4
为什么只有一个bean收到了这个事件?
PS。按要求添加bean文件。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="customEventHandler" class="customevents.di.CustomEventHandler" scope="prototype">
</bean>
<bean id="customEventPublisher" class="customevents.di.CustomEventPublisher">
</bean>
</beans>
答案 0 :(得分:1)
Staphanee Nicoll在spring blog post中描述如下:
事件的实际处理将遵循您设置的语义 在你的豆子上。因此,如果您设置原型,我们将创建一个新的 在调用方法之前为你的bean的实例。我们是 为每个活动做这件事。如果您希望所有现有 要为特定事件调用的原型实例,事实并非如此 将要发生的事情(我们从未做过多播事件 基础设施并不意味着这样做。)
您错过了添加cvp.publish()
来调用每个自定义事件处理程序。
static
部分
希望它能奏效。
要了解更多信息,您可以阅读本教程:Custom events in spring
答案 1 :(得分:1)
您面临的问题似乎是弹簧的限制,至少在某些旧版本中,应该已经修复。有些用户报告说它仍然坏了,所以如果你使用的是一个应该有效的弹簧版本,你可能需要提交一张票。
我找到了以下门票:
答案 2 :(得分:1)
Spring将在上下文启动时注册侦听器。因此,它将在事件触发时创建bean的新实例。
但您也可以在运行时注册侦听器实例( context.addApplicationListener(ce); ),使用如下内容:
public static void main(String[] args) {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
CustomEventPublisher cvp = (CustomEventPublisher) context.getBean("customEventPublisher");
// Scope of these beans is prototype
CustomEventHandler ce = (CustomEventHandler) context.getBean("customEventHandler");
context.addApplicationListener(ce);
CustomEventHandler ce1 = (CustomEventHandler) context.getBean("customEventHandler");
context.addApplicationListener(ce1);
CustomEventHandler ce2 = (CustomEventHandler) context.getBean("customEventHandler");
context.addApplicationListener(ce2);
cvp.publish();
}
答案 3 :(得分:0)
这里的关键是ApplicationListener
实例在ApplicationContext
启动期间注册(请查看ApplicationEventMulticaster
及其实现)。
在您的情况下,这意味着已注册的ApplicationListener
实例实际上是customEventHandler
中定义了标识为Beans.xml
的原型作用域bean,它是处理您发布的事件的那个。< / p>
您应该做的是从应用程序上下文中获取ApplicationEventMulticaster
并使用它来注册在运行时创建的bean。
答案 4 :(得分:0)
确实只有第四个bean被通知了。但是最后一个豆是你自己没有创造的(因为你只召唤了getBean
三次)。
如果从代码中删除cvp.publish()
行,您将看到只创建了三个bean。
第4个实际上是在事件调度期间创建的。行为由AbstractApplicationEventMulticaster中的代码解释。它只存储实现ApplicationListener
的bean名称,然后在需要通知侦听器时执行BeanFactory.getBean()
。
以下是相关代码(方法getApplicationListeners()
,版本4.0.3.RELEASE):
for (String listenerBeanName : listenerBeans) {
try {
Class<?> listenerType = beanFactory.getType(listenerBeanName);
if (listenerType == null || supportsEvent(listenerType, event)) {
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
retriever.applicationListenerBeans.add(listenerBeanName);
allListeners.add(listener);
}
}
}
catch (NoSuchBeanDefinitionException ex) {
// Singleton listener instance (without backing bean definition) disappeared -
// probably in the middle of the destruction phase
}
}
如果您认为prototype
bean毕竟只是一个&#34;原型&#34;那么这是有意义的。 /&#34;模板&#34;。容器没有为创建的实际实例保留引用。它会在需要时调用getBean()
,这将导致一个新实例。