SpringBoot 提供了各种各样的时间监听器( ApplicationListener 的子类 ),用来订阅SpringBoot在运行阶段的各种事件,整体的这种方式实现的逻辑图如下图:

这个接口是应用的事件的监听器,基于观察者模式实现,从Spring3.0开始,当监听器在Spring上下文注册后, 在Spring的某些阶段出现发出事件的时候,将会执行指定的方法。
@FunctionalInterfacepublic interface ApplicationListener<E extends ApplicationEvent> extends EventListener {/** 处理一个应用事件*/void onApplicationEvent(E event);}
这里的消息指的是 ApplicationEvent, Spring 提供了ApplicationEvent 类,并内置一些Spring的应用事件,如果需要定义自定义的事件,则需要通过继承 ApplicationEvent实现。
SpringBoot 内置的SpringApplicationEvent如下图所示。

SpringBoot 的事件发送时具有一定顺序,会按照SpringBoot的启动顺序发送:

通过继承ApplicationListener<E> 可以实现自定义的事件处理器,下面的代码中展示了监听ApplicationEvent事件的功能
/*** 自定义的事件监听器,监听事件为 ApplicationEvent*/@Slf4j@Componentpublic class CustomerApplicationListener implements ApplicationListener<ApplicationEvent> {@Overridepublic void onApplicationEvent(ApplicationEvent e) {log.info("接收到 Spring事件 => {}", e.getClass().getSimpleName());}}// 启动应用后,可以在控制台看到应用的相关事件,控制台打印结果如下接收到 Spring事件 => ServletWebServerInitial接收到 Spring事件 => ContextRefreshedEvent接收到 Spring事件 => ApplicationStartedEvent接收到 Spring事件 => AvailabilityChangeEvent接收到 Spring事件 => ApplicationReadyEvent接收到 Spring事件 => AvailabilityChangeEvent
事实上,我们也可以通过自定义事件的方式,实现自己的相关的业务逻辑。比如下面的代码中展示了在Spring应用启动完成后会发送一个自定义的消息, 同样的此消息必须继承自ApplicationEvent 下面的代码中定义了CustomerEvent。
@Getter@Setterpublic class OrderPayEvent extends ApplicationEvent {private final String content;private final Long time;public MyCustomerEvent(String content) {super("自定义的事件源");this.content = content;this.time = System.currentTimeMillis();}}
在需要的地方使用SpringBoot的上下文 ApplicationContext 发布事件, 那么相应的自定义消息处理器的就会接收到消息。
**
默认情况下,接收事件的发送和处理在同一个线程,但是可以通过 **
@Async和@EnableAsync** 启用异步处理。
// 通过SpringBoot上下文发送事件context.publishEvent(new OrderPayEvent("这是自定义的应用启动完成消息"));/*** 自定义的事件监听器,监听事件为 OrderPayEvent** @apiNote 如果需要异步处理能力的话,添加此注解,注意SpringBoot应用需要添加@EnableAsync注解,否则该注解不生效*/@Slf4j@Componentpublic class CustomerEventListener implements ApplicationListener<OrderPayEvent> {@Async@Overridepublic void onApplicationEvent(OrderPayEvent e) {log.info("接收到 自定义的事件 => {}", e.getClass().getSimpleName());log.info("事件内容 => {}", e.getContent());log.info("接收到消息的线程 ==> {}", Thread.currentThread().getName());}}// 控制台输出结果发送消息的线程:main接收到 自定义的事件 => OrderPayEvent事件内容 => 这是自定义的应用启动完成消息接收到消息的线程 ==> task-1
本质上,SpringBoot 通过应用事件广播器ApplicationEventMulticaster 的方式实现事件监听器的注册和管理以及事件的发送 。
public interface ApplicationEventMulticaster {// 新增事件监听器void addApplicationListener(ApplicationListener<?> listener);// 新增事件监听器void addApplicationListenerBean(String listenerBeanName);// 移除事件监听器void removeApplicationListener(ApplicationListener<?> listener);// 移除事件监听器void removeApplicationListenerBean(String listenerBeanName);// 移除全部事件监听器void removeAllListeners();// 发送应用事件void multicastEvent(ApplicationEvent event);// 发送应用事件void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);}
通过查看 ApplicationContext 源码的方式可以看到其publicEvent的源码调用了multicastEvent 方法发送应用事件。
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {Assert.notNull(event, "Event must not be null");// Decorate event as an ApplicationEvent if necessaryApplicationEvent applicationEvent;if (event instanceof ApplicationEvent) {applicationEvent = (ApplicationEvent) event;}else {applicationEvent = new PayloadApplicationEvent<>(this, event);if (eventType == null) {eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType();}}// Multicast right now if possible - or lazily once the multicaster is initializedif (this.earlyApplicationEvents != null) {this.earlyApplicationEvents.add(applicationEvent);}else {// 此处获取到 ApplicationEventMulticaster 实例后发送消息getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);}// Publish event via parent context as well...if (this.parent != null) {if (this.parent instanceof AbstractApplicationContext) {((AbstractApplicationContext) this.parent).publishEvent(event, eventType);}else {this.parent.publishEvent(event);}}}
- 拓展阅读
