有道无术,术尚可求,有术无道,止于术。
本系列Spring Boot版本2.7.0
紧接上文,接下来分析下面这几步:
ConfigurableApplicationContext context = null;
// 配置Headless
configureHeadlessProperty();
// 获取监听器集合
SpringApplicationRunListeners listeners = getRunListeners(args);
// 调用监听器启动方法
listeners.starting(bootstrapContext, this.mainApplicationClass);
ConfigurableApplicationContext
是Spring 提供的接口,翻译过来就是可配置应用上下文的意思,可以看到它继承了很多接口,上一级继承的接口有:
该接口的源码如下:
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
// 配置文件路径分隔符,主要用来分割各个配置文件路径
String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
// 转换服务的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 容器。
SpringApplicationRunListener
是Spring Boot
提供的接口,从字面上看,它是一个Spring 应用启动监听器。
学过Spring 的应该知道,有个事件监听器机制,是在观察者模式基础上的进一步抽象和改进,定义了一个ApplicationListener
接口作为事件监听器的抽象,当监听的事件在容器中被发布,onApplicationEvent
方法将被调用。
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
/**
* Handle an application event.
* @param event the event to respond to
*/
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 */
@Deprecated
default void started(ConfigurableApplicationContext context) {
}
// 当应用程序上下文已刷新且所有{@link CommandLineRunner CommandLineRunner}和{@link ApplicationRunner ApplicationRunners}已调用。
default void ready(ConfigurableApplicationContext context, Duration timeTaken) {
this.running(context);
}
/** @deprecated */
@Deprecated
default void running(ConfigurableApplicationContext context) {
}
// 运行应用程序时发生故障时调用。
default void failed(ConfigurableApplicationContext context, Throwable exception) {
}
}
ApplicationListener
是Spring 中的监听器接口,可以看到在spring.factories
中定义了7种监听器。
SpringApplication
对象在创建的时候,会去获取这些监听器。
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// ..........
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
}
ApplicationStartup
字面上看是应用启动的意思,它的作用是标记应用程序启动期间的步骤,并收集有关执行上下文或其处理时间的数据。
该接口只有一个start
方法,传入一个步骤名称参数,描述当前操作或阶段,然后创建一个步骤对象并标记它的开始,然后返回当前StartupStep
(启动步骤)对象。
public interface ApplicationStartup {
ApplicationStartup DEFAULT = new DefaultApplicationStartup();
StartupStep start(String name);
}
可理解为当前接口的功能就是记录每一个启动步骤的相关检测数据。
private 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
模式,告诉程序当前环境没有外设,需要依靠系统的计算能力模拟出这些外设特性。
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, Consumer<SpringApplicationRunListener> listenerAction, Consumer<StartupStep> 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<ApplicationListener<?>> 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<ApplicationListener<?>> 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 Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable AbstractApplicationEventMulticaster.CachedListenerRetriever retriever) {
// 1. 创建一个集合对象,用于存放ApplicationListener(spring 提供的监听器)
List<ApplicationListener<?>> allListeners = new ArrayList();
Set<ApplicationListener<?>> filteredListeners = retriever != null ? new LinkedHashSet() : null;
Set<String> 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<ApplicationListener<ApplicationEvent>> delegates = this.getListeners(((ApplicationEnvironmentPreparedEvent)event).getEnvironment());
if (delegates.isEmpty()) {
return;
}
this.multicaster = new SimpleApplicationEventMulticaster();
Iterator var3 = delegates.iterator();
while(var3.hasNext()) {
ApplicationListener<ApplicationEvent> listener = (ApplicationListener)var3.next();
this.multicaster.addApplicationListener(listener);
}
}
if (this.multicaster != null) {
this.multicaster.multicastEvent(event);
}
}
最后,监听器执行完毕,启动开始阶段标记为结束。
SpringApplicationRunListener
,调用starting
开始启动;spring.boot.application.starting
,调用EventPublishingRunListener
进行事件广播;ApplicationListener
并过滤,最后有三个支持当前事件的监听器;onApplicationEvent
方法,最终只有LoggingApplicationListener
(日志监听器)实际执行了处理(初始化日志系统);