SpringBoot启动过程:
上一节我们讨论SpringApplication实例化的过程,也就是上图1-5步骤,本节我们讨论6-9的关键步骤,现在主要讲是run方法里面的过程
/*** 启动方法* @param args* @return*/public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;this.configureHeadlessProperty();//获取所有的启动监听器SpringApplicationRunListeners listeners = this.getRunListeners(args);//发布正在开始的事件listeners.starting();try {//包装参数变量ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//准备环境ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);this.configureIgnoreBeanInfo(environment);Banner printedBanner = this.printBanner(environment);context = this.createApplicationContext();this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);this.refreshContext(context);this.afterRefresh(context, applicationArguments);stopWatch.stop();if (this.logStartupInfo) {(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);}listeners.started(context);this.callRunners(context, applicationArguments);} catch (Throwable var9) {this.handleRunFailure(context, var9, listeners);throw new IllegalStateException(var9);}try {listeners.running(context);return context;} catch (Throwable var8) {this.handleRunFailure(context, var8, (SpringApplicationRunListeners)null);throw new IllegalStateException(var8);}}
获取并启用监听器
这一步 通过监听器来实现初始化的的基本操作,这一步做了2件事情
- 创建所有 SpringBoot
运行监听器
并发布应用启动事件 - 启用监听器
获取运行监听器
我们知道上一节我们在实例化SpringApplication的时候有获取所有监听器的动作,这里的获取监听器,是获取SpringBoot的启动监听器,完成不是一个概念的,这样我们就可以在SpringBoot启动过程中,嵌入我们扩展点,比如在SpringBoot启动时加载我们字典值,或者是环境需要的必要配置等,都可以。获取运行监听器代码如下:
/*** 包装所有运行监听器,返回监听器 manger* @param args* @return*/private SpringApplicationRunListeners getRunListeners(String[] args) {Class<?>[] types = new Class[]{SpringApplication.class, String[].class};return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));}
从代码我们可以看出来,也是重复的代码调用,从META-INF/spring.factories获取所有的实现类,我先看看具体有哪些方法:
public interface SpringApplicationRunListener {//正则启动作用的逻辑default void starting() {}//环境准备后,发布的时间方法default void environmentPrepared(ConfigurableEnvironment environment) {}//容器准备前,调用的逻辑default void contextPrepared(ConfigurableApplicationContext context) {}//容器加载后,调用的逻辑default void contextLoaded(ConfigurableApplicationContext context) {}//SpringBoot 开始后方法调用完后逻辑default void started(ConfigurableApplicationContext context) {}//SpringBoot 运作中调用的逻辑default void running(ConfigurableApplicationContext context) {}//失败调用的逻辑default void failed(ConfigurableApplicationContext context, Throwable exception) {}}
我们可以自己现实上面的启动监听器,然后再resources创建META-INF/spring.factories文件,把key全限定名接口,值是我们自定义的启动监听类,SpringBoot启动时,每一个阶段都会调用我们自定义类的方法。
启动监听
下面我们看看SpringBoot是如何调用启动监听对应的方法的,我们现在以listeners.starting();
方法调用为例,只要弄明白这个方法的调用,其他阶段也是依次类推。代码如下
class SpringApplicationRunListeners {private final Log log;private final List<SpringApplicationRunListener> listeners;SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {this.log = log;this.listeners = new ArrayList<>(listeners);}void starting() {Iterator<SpringApplicationRunListener> it = this.listeners.iterator();//遍历调用所有的启动监听器while(it.hasNext()) {SpringApplicationRunListener listener = it.next();listener.starting();}}
代码很简单,SpringBoot用SpringApplicationRunListeners类把所有启动监听器都管理启动,通过他发布对应事件,然后循环去调用对应启动监听器的事件,而SpringBoot默认只要一个org.springframework.boot.context.event.EventPublishingRunListener
启动监听器,通过他可以做很多很多的事情,下面我们会一步一步分析。
EventPublishingRunListener
在上一步实例化监听器的时候,会传入对应的SpringApplication对象,然后从该对象中,取出所有的监听器,这里的监听器是SpringApplication对象初始化的
public EventPublishingRunListener(SpringApplication application, String[] args) {this.application = application;this.args = args;//初始化一个简单应用事件广播器this.initialMulticaster = new SimpleApplicationEventMulticaster();Iterator<ApplicationListener> it = application.getListeners().iterator();//遍历所有的监听器,添加到广播器中while (it.hasNext()) {ApplicationListener<?> listener = (ApplicationListener) it.next();this.initialMulticaster.addApplicationListener(listener);}}
EventPublishingRunListener派发事件
EventPublishingRunListener派发正在开始事件,然后上一步我们添加的监听器就可以监听到事件触发,执行对应逻辑。
public void starting() {this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));}
广播器继续调用广播事件的方法org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent
/*** 广播事件* @param event 事件本身* @param eventType 事件类型*/public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);//获取一个执行器,这里应该是null的Executor executor = this.getTaskExecutor();//获取匹配到的监听器,不同版本可能有差异Iterator<ApplicationListener> it = this.getApplicationListeners(event, type).iterator();while(it.hasNext()) {ApplicationListener<?> listener = (ApplicationListener)it.next();if (executor != null) {executor.execute(() -> {this.invokeListener(listener, event);});} else {//调用监听器this.invokeListener(listener, event);}}}
我们再来看看寻找监听器列表过程,因为SpringBoot初始化的是,给了我们很多监听器,但是并不一定每个监听器都支持该事件的响应,我们需要过滤出支持正在开始事件的监听器。调用的是 this.getApplicationListeners(event, type)
方法,上一步的
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {Object source = event.getSource();Class<?> sourceType = source != null ? source.getClass() : null;//以事件类型和事件源构建一个keyListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);CachedListenerRetriever newRetriever = null;CachedListenerRetriever existingRetriever = (CachedListenerRetriever)this.retrieverCache.get(cacheKey);if (existingRetriever == null && (this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {//不存在会构建一个取回器,放到缓存中,newRetriever 会传到retrieveApplicationListeners方法里面赋很多值newRetriever = new CachedListenerRetriever();existingRetriever = (CachedListenerRetriever)this.retrieverCache.putIfAbsent(cacheKey, newRetriever);if (existingRetriever != null) {newRetriever = null;}}//存在的话直接返回监听器列表if (existingRetriever != null) {Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();if (result != null) {return result;}}return this.retrieveApplicationListeners(eventType, sourceType, newRetriever);}
这个方法非常简单,就是根据事件类型和事件源的类型生成一个缓存的KEY,如果没有就新增重新添加进去。这里我们是第一次进这个方法,应该是没有,代码来到this.retrieveApplicationListeners(eventType, sourceType, newRetriever);
取回事件监听器
/*** 取回事件监听器* @param eventType 事件类型* @param sourceType 事件源类型* @param retriever 取回者,监听器会在里面* @return 返回监听列表*/private Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable AbstractApplicationEventMulticaster.CachedListenerRetriever retriever) {List<ApplicationListener<?>> allListeners = new ArrayList<>();Set<ApplicationListener<?>> filteredListeners = retriever != null ? new LinkedHashSet<>() : null;Set<String> filteredListenerBeans = retriever != null ? new LinkedHashSet<>() : null;LinkedHashSet listeners;LinkedHashSet listenerBeans;synchronized(this.defaultRetriever) {//取出所有的监听器listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);}Iterator<ApplicationListener> it = listeners.iterator();while(it.hasNext()) {ApplicationListener<?> listener = (ApplicationListener)it.next();//判断是否支持该事件的监听器if (this.supportsEvent(listener, eventType, sourceType)) {if (retriever != null) {filteredListeners.add(listener);}allListeners.add(listener);}}//省略调不重要的代码。。。。//.....................AnnotationAwareOrderComparator.sort(allListeners);//放回结果return allListeners;}
我们再来看看this.supportsEvent(listener, eventType, sourceType)
方法它是如何判断是否支持的,源码如下:
/*** 是否支持事件* @param listener* @param eventType* @param sourceType* @return*/protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {//判断该监听器是否是GenericApplicationListener类型,如果不是需要用GenericApplicationListenerAdapter保证GenericApplicationListener smartListener = listener instanceof GenericApplicationListener ? (GenericApplicationListener)listener : new GenericApplicationListenerAdapter(listener);//调用 GenericApplicationListener的supportsEventType和supportsSourceType判断return ((GenericApplicationListener)smartListener).supportsEventType(eventType) && ((GenericApplicationListener)smartListener).supportsSourceType(sourceType);}
上述代码注释已经写的很清楚了,GenericApplicationListener 类型的监听器,子类会实现对应的两个方法,如果不是GenericApplicationListener ,需要使用适配类包装一下,然后使用监听器的泛型类型去判断(个人猜想),这里代码有点底层,有时间再去研究研究。
###调用监听器
匹配到的监听器我们已经找到了,现在就是循环遍历所有监听器,调用的处理事件,方法如下:
this.invokeListener(listener, event);
最后调用用实际的监听器的处理
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {try {listener.onApplicationEvent(event);} catch (ClassCastException var6) {String msg = var6.getMessage();if (msg != null && !this.matchesClassCastMessage(msg, event.getClass())) {throw var6;}Log logger = LogFactory.getLog(this.getClass());if (logger.isTraceEnabled()) {logger.trace("Non-matching event type for listener: " + listener, var6);}}}
在发布ApplicationStartingEvent
事件的时候,我们通过debuger知道符合条件的只有4个监听器,真正做事只有两个监听器,剩下两个事件的处理方法是空的。
-
LoggingApplicationListener
: 完成日志系统的监听器 -
BackgroundPreinitializer
: 执行预初始化,使用多线程新增了五个对象 -
CharsetInitializer
: 字符集相关初始化 -
ValidationInitializer
: 校验相关的初始化器 -
MessageConverterInitializer
: 信息转换的初始化器 -
JacksonInitializer
: json相关的初始化器 -
ConversionServiceInitializer
: 对象相关服务初始化器
##总结
本节主要讲解监听器的发布事件,还有触发事件的处理逻辑,详情步骤如下:
run方法中SpringApplicationRunListeners#starting =>
遍历SpringApplicationRunListener#starting=>
主要是EventPublishingRunListener#multicastEven这对象广发事件 =>
寻找适合该事件的监听器 =>
调用各个监听器的处理方法 =>
结束
从SpringApplicationRunListener
接口中可以看出,总共是七大事件,目前我们这里介绍了第一个事件的处理逻辑,剩下的事件处理大致一样,不会在细讲,最多讲一下各个监听器处理内容。