Events使用介绍
在ApplicationContext中,事件处理通过ApplicationEvent类和ApplicationListener接口提供。如果将实现ApplicationListener接口的bean部署到上下文中,每当一个ApplicationEvent被发布到ApplicationContext时,该bean将被通知。本质上,这是标准的观察者设计模式。官网地址
从Spring 4.2开始,事件基础设施得到了显著改进,并提供了基于注解的模型,以及发布任意事件的能力(即,并不一定要扩展自ApplicationEvent的对象)。当发布这样的对象时,我们会为您封装成一个事件。
下表描述了Spring提供的标准事件:
事件名称 | 描述 |
---|---|
ContextRefreshedEvent | 当ApplicationContext被初始化或刷新时发布。这通常发生在容器初始化完成并准备好接受请求时。 |
ContextStartedEvent | 当通过调用ApplicationContext的start()方法启动上下文时发布。 |
ContextStoppedEvent | 当通过调用ApplicationContext的stop()方法停止上下文时发布。 |
ContextClosedEvent | 当通过调用ApplicationContext的close()方法关闭上下文时发布。 |
RequestHandledEvent | 在Web应用程序中,当一个HTTP请求被处理完毕后发布。 |
ServletRequestHandledEvent | 在Web应用程序中,当一个HTTP请求被处理完毕后发布。它与RequestHandledEvent类似,但提供了更多与Servlet相关的信息。 |
这些标准事件提供了对应用程序上下文的生命周期和请求处理的跟踪和处理能力。您还可以定义和发布自定义事件,以满足应用程序的特定需求。以下示例显示了一个扩展 Spring 的 ApplicationEvent 基类的简单类:
package com.qhyu.cloud.springEvent;import org.springframework.context.ApplicationContext;
import org.springframework.context.event.ApplicationContextEvent;import java.io.Serializable;/*** Title:BlockedListEvent <br>* Package:com.qhyu.cloud.springEvent <br>* @author piano <br>* date 2023年 10月08日 10:23 <br>* @version v1.0 <br>*/
public class BlockedListEvent extends ApplicationContextEvent implements Serializable {private static final long serialVersionUID = 1L;private final String address;private final String content;/*** Create a new ContextStartedEvent.* @param source the {@code ApplicationContext} that the event is raised for* (must not be {@code null})*/public BlockedListEvent(ApplicationContext source, String address, String content) {super(source);this.address = address;this.content = content;}public String getAddress() {return address;}public String getContent() {return content;}
}
要发布自定义的ApplicationEvent,可以在ApplicationEventPublisher上调用publishEvent()方法。通常,可以通过创建一个实现ApplicationEventPublisherAware接口的类,并将其注册为Spring bean来完成这一操作。以下示例展示了这样一个类:
package com.qhyu.cloud.springEvent;import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;/*** Title:EmailService <br>* Package:com.qhyu.cloud.springEvent <br>* @author piano <br>* date 2023年 10月08日 10:28 <br>* @version v1.0 <br>*/
@Component
public class EmailService implements ApplicationEventPublisherAware, ApplicationContextAware {// 使用ApplicationEventPublisher应用事件发布器发布事件private ApplicationEventPublisher applicationEventPublisher;private ApplicationContext applicationContext;@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.applicationEventPublisher = applicationEventPublisher;}public void sendEmail(String address, String content) {applicationEventPublisher.publishEvent(new BlockedListEvent(applicationContext, address, content));}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext=applicationContext;}
}
在配置时,Spring容器检测到EmailService实现了ApplicationEventPublisherAware接口,并自动调用setApplicationEventPublisher()方法。实际上,传递的参数是Spring容器本身。您通过其ApplicationEventPublisher接口与应用程序上下文进行交互。
要接收自定义的ApplicationEvent,可以创建一个实现ApplicationListener接口的类,并将其注册为Spring bean。以下示例展示了这样一个类:
package com.qhyu.cloud.springEvent;import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;/*** Title:BlockedListNotifier <br>* Package:com.qhyu.cloud.springEvent <br>* @author piano <br>* date 2023年 10月08日 10:33 <br>* @version v1.0 <br>*/
@Component
public class BlockedListNotifier implements ApplicationListener<BlockedListEvent> {@Overridepublic void onApplicationEvent(BlockedListEvent event) {System.out.println("地址:"+event.getAddress());System.out.println("内容:"+event.getContent());}
}
结果如下:
请注意,ApplicationListener使用泛型参数化为您的自定义事件类型(在前面的示例中为BlockedListEvent)。这意味着onApplicationEvent()方法可以保持类型安全,避免了任何需要进行向下转型的情况。您可以注册任意数量的事件监听器,但请注意,默认情况下,事件监听器会同步接收事件。这意味着publishEvent()方法将会阻塞,直到所有监听器完成对事件的处理。这种同步和单线程的方法的一个优点是,当监听器接收到事件时,如果存在事务上下文,它将在发布者的事务上下文中运行。如果需要使用其他策略进行事件发布,例如默认情况下进行异步事件处理,请参阅Spring的ApplicationEventMulticaster接口和SimpleApplicationEventMulticaster实现的Javadoc,了解可应用于自定义"applicationEventMulticaster" bean定义的配置选项。
Spring的事件机制旨在实现在同一个应用程序上下文中的Spring bean之间进行简单通信。然而,对于更复杂的企业集成需求,独立维护的Spring Integration项目提供了完整的支持,用于构建基于轻量级、面向模式、事件驱动架构的解决方案,这些解决方案建立在众所周知的Spring编程模型之上。
源码解析
initApplicationEventMulticaster
initApplicationEventMulticaster
是Spring框架中的一个方法,用于初始化应用程序事件广播器(ApplicationEventMulticaster)。
在Spring框架中,事件是通过应用程序事件广播器进行发布和传播的。当某个事件发生时,广播器负责将事件通知给对该事件感兴趣的监听器。
initApplicationEventMulticaster
方法通常在Spring应用程序的上下文初始化过程中被调用。它的作用是创建并配置应用程序事件广播器,并将其注册到Spring上下文中。
具体来说,initApplicationEventMulticaster
方法会执行以下任务:
-
创建应用程序事件广播器:根据配置和上下文环境,创建适当的应用程序事件广播器实例。在Spring中,通常使用
SimpleApplicationEventMulticaster
作为默认的事件广播器实现。 -
配置应用程序事件广播器:根据配置和需求,对应用程序事件广播器进行一些配置。例如,可以设置广播器的异步执行模式、任务执行器、异常处理器等。
-
注册应用程序事件广播器:将创建和配置好的应用程序事件广播器注册到Spring上下文中,以便在需要时可以使用。
通过初始化应用程序事件广播器,Spring框架可以实现事件驱动的编程模型。开发者可以定义自己的事件类,并编写监听器来处理这些事件。然后,通过应用程序事件广播器将事件传播给对应的监听器,从而实现解耦和模块间的协作。
需要注意的是,initApplicationEventMulticaster
方法通常由Spring框架自动调用,开发者一般无需手动调用该方法。它是Spring容器内部的一个初始化过程,用于确保应用程序事件广播器的正确配置和注册。
protected void initApplicationEventMulticaster() {ConfigurableListableBeanFactory beanFactory = getBeanFactory();if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {this.applicationEventMulticaster =beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);if (logger.isTraceEnabled()) {logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");}}else {// 广播器的创建SimpleApplicationEventMulticasterthis.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);if (logger.isTraceEnabled()) {logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");}}}
registerListeners
registerListeners
是Spring框架中的一个方法,用于向应用程序事件广播器(ApplicationEventMulticaster)注册监听器。
在Spring框架中,事件是通过应用程序事件广播器进行发布和传播的。监听器是用于接收和处理特定事件的组件。通过将监听器注册到应用程序事件广播器中,可以实现对事件的监听和响应。
registerListeners
方法通常在Spring应用程序的上下文初始化过程中被调用。它的作用是将应用程序中定义的监听器注册到应用程序事件广播器中,使其能够接收和处理相应的事件。
具体来说,registerListeners
方法会执行以下任务:
-
扫描应用程序上下文:遍历应用程序上下文中的所有Bean,查找实现了
ApplicationListener
接口的监听器Bean。 -
注册监听器:将扫描到的监听器Bean注册到应用程序事件广播器中,以便在事件发布时能够接收到相应的事件。
通过registerListeners
方法,Spring框架可以自动将监听器注册到应用程序事件广播器中,无需手动编写注册代码。这样,当某个事件发生时,应用程序事件广播器会自动将事件通知给已注册的监听器,从而触发监听器中定义的处理逻辑。
需要注意的是,registerListeners
方法通常由Spring框架自动调用,开发者无需手动调用该方法。它是Spring容器内部的一个初始化过程,用于自动注册监听器。开发者只需要实现相应的监听器接口,然后在Spring配置中声明监听器的Bean,即可实现对事件的监听和处理。
protected void registerListeners() {// Register statically specified listeners first.for (ApplicationListener<?> listener : getApplicationListeners()) {getApplicationEventMulticaster().addApplicationListener(listener);}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let post-processors apply to them!String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);for (String listenerBeanName : listenerBeanNames) {getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}// Publish early application events now that we finally have a multicaster...Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;this.earlyApplicationEvents = null;if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {for (ApplicationEvent earlyEvent : earlyEventsToProcess) {getApplicationEventMulticaster().multicastEvent(earlyEvent);}}}