springboot2.x初探(二)

这篇文章接着 springboot2.x初探(一)

springboot2.x初探(二)

上篇文章中我们对 1 处的代码进行了分析,这篇文章来继续分析 2 处的代码:

springboot2.x初探(二)

springboot2.x初探(二)

由于这个方法比较长所以截了两个图,下面我们就按照截图中步骤的编号来一个一个看。

我们先来看看 1 处的StopWatch是什么

springboot2.x初探(二)

从类上的注释可以知道,这就是一个简单的记录开始时间和结束时间的功能的封装,它是非线程安全的。它的start 方法如下:

springboot2.x初探(二)

可以看到就是记录了一个任务名字为空的任务的开始时间。

4处的 SpringBootExceptionReporter:

springboot2.x初探(二)

它就是应用启动过程中发生错误的时候给用户抛出异常用的。

5 处的配置 java.awt.headless 属性的值,默认为 true

这个  java.awt.headless 是做什么用的呢?查到了一篇这样的博客:

https://blog.****.net/wodeyuer125/article/details/50502914

springboot2.x初探(二)

6 处的监听器:

springboot2.x初探(二)

它是SpringApplication 的run方法的监听器。

springboot2.x初探(二)

它的 starting方法会在run方法开始的时候马上调用。

通过 getRunListeners方法获取 SpringApplicationRunListener类的实现类的实例:

springboot2.x初探(二)

看一个listener实现类:

springboot2.x初探(二)

7处的starting

springboot2.x初探(二)

这里的 initialMulticaster :

springboot2.x初探(二)

先看看这个 SpringApplicationRunListener的实现类:

springboot2.x初探(二)

它使用一个内部的广播器来在context刷新之前发布触发的事件。

springboot2.x初探(二)

它就是将事件广播给所有注册的监听器,让监听器忽略不感兴趣的事件。

具体的广播方法在SimpleApplicationEventMulticaster类中,如下:

springboot2.x初探(二)

可以看到每个listener都使用了一个executor来调用,其中调用了一个 resolveDefaultEventType的方法,

springboot2.x初探(二)

springboot2.x初探(二)

这里有个判断判断传入的参数是不是 ResolvableTypeProvider的实例,我们上面实例化的是一个ApplicationStartingEvent:

springboot2.x初探(二)

我们看看这个ApplicationStartingEvent是不是实现了ResolvableTypeProvider接口:

springboot2.x初探(二)

springboot2.x初探(二)

springboot2.x初探(二)

springboot2.x初探(二)

这个过程中可以发现这个ApplicationStartingEvent就是对SpringApplication和参数的一个封装,同时很明显,它没有实现ResolvableTypeProvider接口,所以在 forInstance方法中调用的是:

springboot2.x初探(二)

接着看这个 forClass是怎么回事:

springboot2.x初探(二)

为传入的类返回了一个 ResolvableType,

springboot2.x初探(二)

可以看到这个 ResolvableType就是记录传入的类的类型,这个类型做什么用呢?

springboot2.x初探(二)

它在 getApplicationListeners方法中被调用了:

springboot2.x初探(二)

springboot2.x初探(二)

其中的ListenerCacheKey:

springboot2.x初探(二)

springboot2.x初探(二)

这里看到ListenerCacheKey竟然是一个Map的key,它是一个对象但是作为一个key了,那么它肯定重写了 hashcode和equals方法,我们看看:

springboot2.x初探(二)

果然如此,这里面具体的内容不在今天分析范围。接着往下看:

springboot2.x初探(二)

这个ListenerRetriever是一个私有的内部类,

springboot2.x初探(二)

看到这里的时候就有个疑问这个 ListenerRetriever中的applicationListeners是什么时候赋值的?

springboot2.x初探(二)

然后想到了之前的获取runlisteners方法中有获取实例化的runlisteners,看到了其中的types就是构造函数的参数类型,然后把它自己(SpringApplication)和args参数传了进去。

springboot2.x初探(二)

然后看到

springboot2.x初探(二)

这个构造函数中将listener都赋值给了 initialMulticaster,调用的是 SimpleApplicationEventMulticaster的父类的方法

springboot2.x初探(二)

将listener都赋值给了 detaultRetriever,然而在getApplicationListeners方法中有这样一个方法:

springboot2.x初探(二)

我们看看这个方法:

springboot2.x初探(二)

在这个方法中,将detaultRetriever中的applicationListeners返回来了,并赋值给了retriver。

到这里就知道了那个getApplicationListeners方法究竟是从哪里获取的listeners了。

好接着往下看multicastEvent方法:

springboot2.x初探(二)

调用了一个invokeListener方法:

springboot2.x初探(二)

里面调用了 doInvokeListener方法:

springboot2.x初探(二)

最终还是调用了ApplicationListener的onApplicationEvent方法:

springboot2.x初探(二)

都有哪些listeners呢?看个启动过程截图:

springboot2.x初探(二)

我们看一个RestartApplicationListener:

springboot2.x初探(二)

springboot2.x初探(二)

再看一个DelegatingApplicationListener

springboot2.x初探(二)

其他的不挨个看了。

到这里这个starting方法先告一段落。(这里的观察者模式用的很溜呀,下面再补补这方面的知识。)

下面看第八步初始化运行参数

springboot2.x初探(二)

这个ApplicationArguments:

springboot2.x初探(二)

提供SpringApplication运行需要的参数。

springboot2.x初探(二)

我们跟一下代码:

springboot2.x初探(二)

springboot2.x初探(二)

看看parse方法:

springboot2.x初探(二)

就是对参数的解析,然后封装到了CommandLineArgs中,

springboot2.x初探(二)

跟到最后发现是这个:

springboot2.x初探(二)

设置成了一个PropertySource。

这部分的内容实在是很多,所以分成了几篇文章来写,后续的分析将在下篇文章继续。