Spring ApplicationListener 详解
ApplicationEvent 和 ApplicationListener
ApplicationEvent
是个抽象类,里面只有一个构造函数和一个长整型的timestamp;它的实现类表示一类事件,可携带数据。
ApplicationListener
是一个接口,里面只有一个onApplicationEvent方法;这个接口是应用的事件的监听器,当监听器在Spring上下文注册后, 在Spring的某些阶段出现发出事件的时候,将会执行指定的方法。
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/** 处理一个应用事件 */
void onApplicationEvent(E event);
}
ApplicationContext 事件机制是观察者设计模式的实现,通过 ApplicationEvent 类和 ApplicationListener 接口,可以实现 ApplicationContext 事件处理;如果容器中存在 ApplicationListener 的 Bean,当 ApplicationContext 调用 publishEvent 时,对应的 Bean 将会自动触发。
SpringBoot 内置事件
SpringBoot 内置的 SpringApplicationEvent 有:
* ApplicationStartingEvent
* ApplicationEnvironmentPreparedEventEvent
* ApplicationContextInitializedEvent
* ApplicationPreparedEvent
* ApplicationStartedEvent
* ApplicationReadyEvent
* ApplicationFailedEvent
触发条件如下图:
自定义事件监听器
通过继承 ApplicationListener
例如:
/**
* 自定义的事件监听器,监听事件为 ApplicationEvent
*/
@Slf4j
@Component
public class CustomerApplicationListener implements ApplicationListener<ApplicationEvent> {
@Override
public void onApplicationEvent(ApplicationEvent event) {
log.info("接收到 Spring 事件 => {}", event.getClass().getSimpleName());
}
}
启动应用后,控制台打印结果如下:
自定义事件
需要定义自定义的事件,需要通过继承 ApplicationEvent实现;
例如:
@Getter
@Setter
public class CustomerEvent extends ApplicationEvent {
private final String content;
private final Long time;
public CustomerEvent(String content) {
super("自定义的事件源");
this.content = content;
this.time = System.currentTimeMillis();
}
}
在需要的地方使用 SpringBoot 的上下文 ApplicationContext 发布事件, 那么相应的自定义消息处理器的就会接收到消息;
@RestController
@RequestMapping("/api/test")
public class TestController {
@Autowired
private ApplicationContext applicationContext;
@GetMapping(value = "/test")
public Map<String, Object> Test() {
applicationContext.publishEvent(new CustomerEvent("这是自定义的事件"));
return null;
}
}
自定义 CustomerEvent 事件监听器:
/**
* 自定义的事件监听器,监听事件为 CustomerEvent
*/
@Slf4j
@Component
public class CustomerApplicationListener implements ApplicationListener<CustomerEvent> {
@Override
public void onApplicationEvent(CustomerEvent event) {
log.info("接收到 自定义的事件 => {}", event.getClass().getSimpleName());
log.info("事件内容 => {}", event.getContent());
log.info("接收到消息的线程 ==> {}", Thread.currentThread().getName());
}
}
访问Api:http://localhost:8080/api/test/test,触发CustomerEvent;
控制台输出如下:
- 默认情况下,接收事件的发送和处理在同一个线程,但是可以通过 @Async 和 @EnableAsync 启用异步处理。
SpringBoot 应用需要添加 @EnableAsync 注解,否则 @Async 注解不生效
@Slf4j @Component @Async @EnableAsync public class CustomerApplicationListener implements ApplicationListener<CustomerEvent> { @Override public void onApplicationEvent(CustomerEvent event) { log.info("接收到 自定义的事件 => {}", event.getClass().getSimpleName()); log.info("事件内容 => {}", event.getContent()); log.info("接收到消息的线程 ==> {}", Thread.currentThread().getName()); } }
事件监听器的注册和管理及事件的发送
本质上,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);
}
}
}