前言
这节继续监听器。
Spring Boot 中的监听器模式
第一个事件
发布的第一个事件在 run 方法中:
public ConfigurableApplicationContext run(String... args) {
// …………
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
// …………
}
然后,我们进入 getRunListeners(args) 方法中。
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
又见到了熟悉的 getSpringFactoriesInstances方法了,我们去 spring.factoris中看一下SpringApplicationRunListener:
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
嗯,这里只有一个实现。
我们再进入new SpringApplicationRunListeners()方法:
SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList<>(listeners);
}
这个显然就是把 EventPublishingRunListener 赋值给了 listeners。
回到主线run()方法中接着调用了listeners.starting();:
// SpringApplicationRunListeners # starting()
public void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
这里遍历 listeners ,调用starting()。事件上我们知道,listener中就一个EventPublishingRunListener。
所以我们 直接进入EventPublishingRunListener#starting()方法:
@Override
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
ojbk,终于看见发布事件的动作了。
我们来看看,都有谁监听了它:
看到了一个配置文件中的 listener:LoggingApplicationListener,看名字肯定跟日志有关系咯。
这个类太长了,不贴出来了。这个类就是用来启动 Spring Boot 的日志系统。
类注释:
一个配置LoggingSystem的ApplicationListener 。 如果环境包含logging.config属性,它将用于引导日志记录系统,否则将使用默认配置。
Spring Boot 启动时的事件
-
ApplicationStartingEvent
Spring Boot 应用开始运行时发送,此时容器尚未初始化完成。
// SpringApplication # run(String... args) # 301-302 SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); -
ApplicationEnvironmentPreparedEvent
在 Spring 上下文创建之前发送,因为创建 Spring context 需要环境。
// SpringApplication # prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) # 342 listeners.environmentPrepared(environment); -
ApplicationContextInitializedEvent
Spring context 已准备好,初始化器已被调用完成。但 bean definitions 还未被加载。
// SpringApplication # prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) # 368listeners.contextPrepared(context); -
ApplicationPreparedEvent
bean definitions 已加载完,在上下文刷新之前发送。
// SpringApplication # prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) # 387listeners.contextLoaded(context); -
ApplicationStartedEvent
Spring context 已刷新,runners 被调用之前。
// SpringApplication # run(String... args) # 318listeners.started(context); -
ApplicationReadyEvent
runners 被调用之后,表示 Spring Boot 已就绪了。
// SpringApplication # run(String... args) # 327listeners.running(context); -
ApplicationFailedEvent
启动发生异常时,发送此事件。
// SpringApplication # handleRunFailure(ConfigurableApplicationContext context, Throwable exception,Collection<SpringBootExceptionReporter> exceptionReporters, SpringApplicationRunListeners listeners) # 794listeners.failed(context, exception);
实践监听器
-
监听器定义
我们就模仿
LoggingApplicationListener来进行定义。public class OneListener implements GenericApplicationListener { @Override public boolean supportsEventType(ResolvableType eventType) { return eventType.isAssignableFrom(ApplicationStartingEvent.class); } @Override public void onApplicationEvent(ApplicationEvent event) { System.out.println("yes,I am listening to you."); } @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE + 20 +1; }} -
监听器注册
-
配置到
spring.factoriesorg.springframework.context.ApplicationListener=\ com.example.indepthspringboot.springbootlistener.OneListener -
硬编码添加
-
application.properties属性配置context.listener.classes上述两种跟 初始化器类似。不重复实现了。
-
@Component 注解
但是只能用于 容器 创建之后的事件。因为在容器创建之前,该类并没有被加载进去。
@Componentpublic class TwoListener implements GenericApplicationListener { @Override public boolean supportsEventType(ResolvableType eventType) { return eventType.isAssignableFrom(ApplicationStartedEvent.class); } @Override public void onApplicationEvent(ApplicationEvent event) { System.out.println("yes,I am registered. and, I am listening to ApplicationStartedEvent"); }}
然后,我们把监听事件修改为 ApplicationStartingEvent。
哦豁,没有监听成功。
-
总结
Spring Boot 中的监听器,其实是很复杂的。我们这里只是挑选了一部分进行学习。
先泛泛地过一遍,了解其大概原理,这样以后再深入地看的时候,也不会犯怵了。
在翻阅了 Spring Boot 中监听器部分时,还是有不少收获的:
- 了解了 监听器模式 的实践运用。
- 监听器模式的扩展用法。
- 监听的事件还可以用泛型来表示
- ……