文章目录有道无术,术尚可求,有术无道,止于术。
本系列Spring Boot版本2.7.0
- 前言
- 核心类及接口
- ConfigurableApplicationContext
- SpringApplicationRunListener
- ApplicationListener
- ApplicationStartup
- 1. 设置Headless
- 2. 获取监听器
- 3. 开启步骤
- 4. 广播事件
- 5. 调用Spring 监听器
- 总结
紧接上文,接下来分析下面这几步:
ConfigurableApplicationContext context = null; // 配置Headless configureHeadlessProperty(); // 获取监听器集合 SpringApplicationRunListeners listeners = getRunListeners(args); // 调用监听器启动方法 listeners.starting(bootstrapContext, this.mainApplicationClass);核心类及接口 ConfigurableApplicationContext
ConfigurableApplicationContext 是Spring 提供的接口,翻译过来就是可配置应用上下文的意思,可以看到它继承了很多接口,上一级继承的接口有:
- ApplicationContext:引用上下文接口,也就是IOC容器接口
- Lifecycle:容器生命周期接口
- Closeable:JDK释放资源接口
该接口的源码如下:
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
// 配置文件路径分隔符,主要用来分割各个配置文件路径
String CONFIG_LOCATION_DELIMITERS = ",; tn";
// 转换服务的bean 名称,通过这个服务,我们则可以实现类型转换操作
String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
// 工厂中LoadTimeWeaver bean的名称
String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
// 环境{@link-Environment}bean的名称。
String ENVIRONMENT_BEAN_NAME = "environment";
// 系统属性的bean 名称
String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
// 系统环境的bean 名称
String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";
// {@link ApplicationStartup} 的bean 名称
String APPLICATION_STARTUP_BEAN_NAME = "applicationStartup";
// 关闭钩子函数线程名称
String SHUTDOWN_HOOK_THREAD_NAME = "SpringContextShutdownHook";
// 设置应用容器的唯一id
void setId(String id);
// 设置父级容器(上下文)
void setParent(@Nullable ApplicationContext parent);
// 设置当前容器环境
void setEnvironment(ConfigurableEnvironment environment);
// 返回此应用程序上下文的环境,允许进一步自定义
ConfigurableEnvironment getEnvironment();
// 设置ApplicationStartup
void setApplicationStartup(ApplicationStartup applicationStartup);
// 获取 ApplicationStartup
ApplicationStartup getApplicationStartup();
// 添加BeanFactoryPostProcessor
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
// 添加容器监听器,主要是指继承了ApplicationListener的监听器
void addApplicationListener(ApplicationListener> listener);
// 设置类加载器
void setClassLoader(ClassLoader classLoader);
// 注册协议解析器。协议解析器的作用就是根据指定的地址和资源加载期,解析资源并将资源返回
void addProtocolResolver(ProtocolResolver resolver);
// 核心方法:加载|刷新 整个容器
void refresh() throws BeansException, IllegalStateException;
// 注册关闭钩子
void registerShutdownHook();
// 关闭容器
void close();
// 获取容器是否活跃
boolean isActive();
// 获取bean factory
ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
由上可知,ConfigurableApplicationContext 就是Spring Boot中的应用上下文对象,也就是Spring 容器。
SpringApplicationRunListenerSpringApplicationRunListener是Spring Boot提供的接口,从字面上看,它是一个Spring 应用启动监听器。
学过Spring 的应该知道,有个事件监听器机制,是在观察者模式基础上的进一步抽象和改进,定义了一个ApplicationListener接口作为事件监听器的抽象,当监听的事件在容器中被发布,onApplicationEvent方法将被调用。
public interface ApplicationListenerextends EventListener { void onApplicationEvent(E event); }
SpringApplicationRunListener就是用来在整个启动流程中接收不同执行点事件通知的监听者,可以在接口定义中看到,一旦启动阶段发布了事件,该监听器就会观察到事件被做出相应操作。
public interface SpringApplicationRunListener {
// 首次启动run方法时立即调用。可用于非常早期初始化。
default void starting(ConfigurableBootstrapContext bootstrapContext) {
}
// 环境准备就绪,但在{@link ApplicationContext}创建之前。
default void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
}
// 在创建和准备{@link ApplicationContext}后,但在加载源之前调用。
default void contextPrepared(ConfigurableApplicationContext context) {
}
// 在加载应用程序上下文之后但在加载之前调用已刷新。
default void contextLoaded(ConfigurableApplicationContext context) {
}
// 上下文已刷新,应用程序已启动,但{@link CommandLineRunner CommandLineRunner}和{@link ApplicationRunner}未调用。
default void started(ConfigurableApplicationContext context, Duration timeTaken) {
this.started(context);
}
@Deprecated
default void started(ConfigurableApplicationContext context) {
}
// 当应用程序上下文已刷新且所有{@link CommandLineRunner CommandLineRunner}和{@link ApplicationRunner ApplicationRunners}已调用。
default void ready(ConfigurableApplicationContext context, Duration timeTaken) {
this.running(context);
}
@Deprecated
default void running(ConfigurableApplicationContext context) {
}
// 运行应用程序时发生故障时调用。
default void failed(ConfigurableApplicationContext context, Throwable exception) {
}
}
ApplicationListener
ApplicationListener是Spring 中的监听器接口,可以看到在spring.factories中定义了7种监听器。
SpringApplication对象在创建的时候,会去获取这些监听器。
public SpringApplication(ResourceLoader resourceLoader, Class>... primarySources) {
// ..........
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
}
ApplicationStartup
ApplicationStartup 字面上看是应用启动的意思,它的作用是标记应用程序启动期间的步骤,并收集有关执行上下文或其处理时间的数据。
该接口只有一个start方法,传入一个步骤名称参数,描述当前操作或阶段,然后创建一个步骤对象并标记它的开始,然后返回当前StartupStep (启动步骤)对象。
public interface ApplicationStartup {
ApplicationStartup DEFAULT = new DefaultApplicationStartup();
StartupStep start(String name);
}
可理解为当前接口的功能就是记录每一个启动步骤的相关检测数据。
1. 设置Headlessprivate void configureHeadlessProperty() {
// java.awt.headless
System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}
configureHeadlessProperty方法很简单,就是设置了一个java.awt.headless系统参数,默认为true,表示开启Headless(中文无头、无外设的意思)模式。
程序在运行时,可能需要使用外设(显示屏、键盘、鼠标)或者获取外设的信息,但一般部署的服务器是没有这些设备的,这个时候就可以开启Headless模式,告诉程序当前环境没有外设,需要依靠系统的计算能力模拟出这些外设特性。
2. 获取监听器getRunListeners方法获取监听器,返回一个SpringApplicationRunListeners 对象。
private SpringApplicationRunListeners getRunListeners(String[] args) {
// 1. 创建一个数组,存放SpringApplication.class、String[].class
Class>[] types = new Class>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
// SPI机制,从spring.factories 中获取SpringApplicationRunListener实例
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
this.applicationStartup);
}
这里可以看到又是使用SPI 机制从META-INF/spring.factories中获取SpringApplicationRunListener类型的实例,可以在源码spring-boot模块中看到只配置了一个该类型的监听器EventPublishingRunListener。
最后将获取到监听器,放入到SpringApplicationRunListeners 对象的成员属性中:
接着进入到SpringApplicationRunListeners 对象的starting方法,可以看到在该方法中,直接转到了doWithListeners方法,参数为一个字符串,两个为Consumer函数式接口的匿名内部类。
void starting(ConfigurableBootstrapContext bootstrapContext, Class> mainApplicationClass) {
this.doWithListeners("spring.boot.application.starting", (listener) -> {
listener.starting(bootstrapContext);
}, (step) -> {
if (mainApplicationClass != null) {
step.tag("mainApplicationClass", mainApplicationClass.getName());
}
});
}
接着进入到其doWithListeners方法,可以看到在该方法中,会调用所有监听器的starting 方法,并记录一个名称为spring.boot.application.starting 的步骤,所有监听器的starting 方法执行完成后,该步骤结束。
private void doWithListeners(String stepName, Consumer4. 广播事件listenerAction, Consumer stepAction) { // 1. 步骤名为spring.boot.application.starting StartupStep step = this.applicationStartup.start(stepName); // 2. 循环所有监听器,调用其starting 方法 this.listeners.forEach(listenerAction); // 3. 记录步骤标记 if (stepAction != null) { stepAction.accept(step); } // 4. 步骤结束。 step.end(); }
因为默认只有一个EventPublishingRunListener监听器,所以这里会进入到该监听器中,会调用SimpleApplicationEventMulticaster对象的multicastEvent方法,参数为ApplicationStartingEvent,该方法从名字上看是进行事件广播,它的作用是会将启动事件,发布给所有的监听器。
public void starting(ConfigurableBootstrapContext bootstrapContext) {
// 广播事件
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
}
ApplicationStartingEvent对象比较简单,就是一个应用启动事件对象,封装了引导上下文和SpringApplication对象。
接着进入到SimpleApplicationEventMulticaster对象的multicastEvent方法:
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
// 1. 解析事件的类型=》ApplicationStartingEvent
ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
// 2. 获取线程池,初次为NULL
Executor executor = this.getTaskExecutor();
Iterator var5 = this.getApplicationListeners(event, type).iterator();
// 3. 循环获取到的监听器,并调用监听器的监听方法
while(var5.hasNext()) {
ApplicationListener> listener = (ApplicationListener)var5.next();
if (executor != null) {
executor.execute(() -> {
this.invokeListener(listener, event);
});
} else {
// 线程池不存在,所以调用这一步
this.invokeListener(listener, event);
}
}
}
getApplicationListeners方法会获取所有支持当前事件的的监听器,不匹配的提前被排除在外。
protected Collection> getApplicationListeners( ApplicationEvent event, ResolvableType eventType) { // 1. 当前事件的来源,SpringApplication Object source = event.getSource(); Class> sourceType = (source != null ? source.getClass() : null); // 2. 创建缓存的 KEY ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType); // Potential new retriever to populate CachedListenerRetriever newRetriever = null; // 3. 缓存中查询是有 CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey); if (existingRetriever == null) { // Caching a new ListenerRetriever if possible if (this.beanClassLoader == null || (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) { newRetriever = new CachedListenerRetriever(); existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever); if (existingRetriever != null) { newRetriever = null; // no need to populate it in retrieveApplicationListeners } } } if (existingRetriever != null) { Collection > result = existingRetriever.getApplicationListeners(); if (result != null) { return result; } // If result is null, the existing retriever is not fully populated yet by another thread. // Proceed like caching wasn't possible for this current local attempt. } // 4. 缓存中没有,所以进入该方法 return retrieveApplicationListeners(eventType, sourceType, newRetriever); }
因为缓存中没有,所以进入retrieveApplicationListeners方法,查询监听器,是之前SpringApplication对象创建的时候从spring.factries中加载的。
private Collection5. 调用Spring 监听器> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class> sourceType, @Nullable AbstractApplicationEventMulticaster.CachedListenerRetriever retriever) { // 1. 创建一个集合对象,用于存放ApplicationListener(spring 提供的监听器) List > allListeners = new ArrayList(); Set > filteredListeners = retriever != null ? new LinkedHashSet() : null; Set filteredListenerBeans = retriever != null ? new LinkedHashSet() : null; LinkedHashSet listeners; // 所有的ApplicationListener LinkedHashSet listenerBeans; // 从默认的持有着中获取监听器, synchronized(this.defaultRetriever) { listeners = new LinkedHashSet(this.defaultRetriever.applicationListeners); listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans); } Iterator var9 = listeners.iterator(); // 2. 循环所有的ApplicationListener,校验这些监听器是否支持ApplicationStartingEvent 事件 // LoggingApplicationListener,BackgroundPreinitializer,DelegatingApplicationListener while(var9.hasNext()) { ApplicationListener> listener = (ApplicationListener)var9.next(); if (this.supportsEvent(listener, eventType, sourceType)) { if (retriever != null) { filteredListeners.add(listener); } allListeners.add(listener); } } // 3. 没有查到这些监听器的Bean 对象,没有这里为空,直接跳过 // 该方法根据注册的Bean ,去查询是否支持事件,并添加到监听器集合中 if (!listenerBeans.isEmpty()) { ConfigurableBeanFactory beanFactory = this.getBeanFactory(); Iterator var16 = listenerBeans.iterator(); while(var16.hasNext()) { String listenerBeanName = (String)var16.next(); try { if (this.supportsEvent(beanFactory, listenerBeanName, eventType)) { ApplicationListener> listener = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class); if (!allListeners.contains(listener) && this.supportsEvent(listener, eventType, sourceType)) { if (retriever != null) { if (beanFactory.isSingleton(listenerBeanName)) { filteredListeners.add(listener); } else { filteredListenerBeans.add(listenerBeanName); } } allListeners.add(listener); } } else { Object listener = beanFactory.getSingleton(listenerBeanName); if (retriever != null) { filteredListeners.remove(listener); } allListeners.remove(listener); } } catch (NoSuchBeanDefinitionException var13) { } } } AnnotationAwareOrderComparator.sort(allListeners); // 4. 将这些监听器和Bean放入到缓存中 if (retriever != null) { if (filteredListenerBeans.isEmpty()) { retriever.applicationListeners = new LinkedHashSet(allListeners); retriever.applicationListenerBeans = filteredListenerBeans; } else { retriever.applicationListeners = filteredListeners; retriever.applicationListenerBeans = filteredListenerBeans; } } return allListeners; }
接着将符合条件的监听器返回,可以看到,缓存中存放了三个监听器:
接着循环执行执行监听器的doInvokeListener方法,进入调用三个监听器的onApplicationEvent方法。
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
} catch (ClassCastException var6) {
// 省略异常捕获代码
}
}
首先循环的是LoggingApplicationListener(日志监听器),它的作用很重要,会完成日志系统的加载和初始化,默认使用的是Logback日志组件。
private void onApplicationStartingEvent(ApplicationStartingEvent event) {
// 使用ClassLoader 加载日志系统,默认是LogbackLoggingSystem
this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());
// 日志系统初始化
this.loggingSystem.beforeInitialize();
}
接着进入到BackgroundPreinitializer(后台预先初始化监听器),该监听器的作用是将一些比较耗时的组件开启后台线程预先初始化,这里是刚开始启动阶段,所有这里也有没进行操作。
public void onApplicationEvent(SpringApplicationEvent event) {
// 1. 查看spring.backgroundpreinitializer.ignore 配置,是否开启预先初始化
if (ENABLED) {
// 2. 是否环境准备事件,是的话,会开启异步线程,初始化Jackson、Charset、ConversionService、Validation、MessageConverter等
if (event instanceof ApplicationEnvironmentPreparedEvent && preinitializationStarted.compareAndSet(false, true)) {
this.performPreinitialization();
}
if ((event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent) && preinitializationStarted.get()) {
try {
preinitializationComplete.await();
} catch (InterruptedException var3) {
Thread.currentThread().interrupt();
}
}
}
}
接着DelegatingApplicationListener(委托应用监听器),监听到事件后转发给环境变量context.listener.classes指定的那些事件监听器,这里也是跳过,没有任何操作。
public void onApplicationEvent(ApplicationEvent event) {
// 1. 判断是否是环境准备事件,这里是刚启动,所以跳过
if (event instanceof ApplicationEnvironmentPreparedEvent) {
List> delegates = this.getListeners(((ApplicationEnvironmentPreparedEvent)event).getEnvironment());
if (delegates.isEmpty()) {
return;
}
this.multicaster = new SimpleApplicationEventMulticaster();
Iterator var3 = delegates.iterator();
while(var3.hasNext()) {
ApplicationListener listener = (ApplicationListener)var3.next();
this.multicaster.addApplicationListener(listener);
}
}
if (this.multicaster != null) {
this.multicaster.multicastEvent(event);
}
}
最后,监听器执行完毕,启动开始阶段标记为结束。
总结- 获取Spring Boot 自己的监听器SpringApplicationRunListener,调用starting开始启动;
- 创建步骤spring.boot.application.starting ,调用EventPublishingRunListener进行事件广播;
- 获取Spring 监听器ApplicationListener并过滤,最后有三个支持当前事件的监听器;
- 循环调用监听器的onApplicationEvent方法,最终只有LoggingApplicationListener(日志监听器)实际执行了处理(初始化日志系统);
- 执行完成,开始启动步骤标记为结束。



