SpringBoot 提供了各种各样的时间监听器( ApplicationListener 的子类 ),用来订阅SpringBoot在运行阶段的各种事件,整体的这种方式实现的逻辑图如下图:
这个接口是应用的事件的监听器,基于观察者模式实现,从Spring3.0开始,当监听器在Spring上下文注册后, 在Spring的某些阶段出现发出事件的时候,将会执行指定的方法。
@FunctionalInterface
public 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
@Component
public class CustomerApplicationListener implements ApplicationListener<ApplicationEvent> {
@Override
public 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
@Setter
public 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
@Component
public class CustomerEventListener implements ApplicationListener<OrderPayEvent> {
@Async
@Override
public 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 necessary
ApplicationEvent 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 initialized
if (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);
}
}
}
- 拓展阅读