前言
上一篇【SpringBoot深度探究(七)源码探究启动流程之一】主要介绍了SpringApplication在构造方法里做了一些必要的初始化,其中最重要的点就是把初始化器类和监听器类全部都加载进去了。本篇将会接着这一进程继续探索run()方法在后面做的事情。但是要说明的是启动流程将主要针对于如何走的Spring主流程,因为SpringBoot每次发布事件都会把所有的Listener循环一遍,以找到对应此事件感兴趣的Listener,全写出来会使得博客太跳,不利于把控整个主流程。各个Listener起了什么作用的部分有时间会单独开博客讲解,请多多包涵。更多Spring内容进入【Spring解读系列目录】。
SpringApplication.run
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start(); //记录日志时间的,没啥大作用
ConfigurableApplicationContext context = null;//现在没啥大用
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); //错误报告列表,没啥大用
//配置系统属性headless,没啥大用
configureHeadlessProperty();
//这方法做的事情也是从spring.factories里面拿到一个类的实例,并且赋值给this.listeners备用
SpringApplicationRunListeners listeners = getRunListeners(args);
//调用starting()方法
listeners.starting();
try {
/*暂时略,后面具体分析*/
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
进入run()
方法以后先跳过没啥大用的代码,就遇到第一个很重要的方法了getRunListeners(args)
,这个方法本身没啥特别可说的。但是它生成类以及返回的对象SpringApplicationRunListeners listeners
非常的有用,那么先进入方法再说。
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// getSpringFactoriesInstances() 和上篇讲的完全一样的方法
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
注意这里和上篇SpringApplication初始化的时候是一样的getSpringFactoriesInstances()
方法,这里去文件spring.factories
里面寻找并且实例化的类型是SpringApplicationRunListener。通过调试和查找最终这里只有一个类被实例化出来。然后通过构造方法SpringApplicationRunListeners()
,赋值给this.listeners
备用。
所有spring.factories文件里只有一个 SpringApplicationRunListeners类型:
// org.springframework.boot.SpringApplicationRunListener=\
// org.springframework.boot.context.event.EventPublishingRunListener
注意,这里的this.listeners
是SpringApplicationRunListeners类的,而上一篇的this.listeners
则是SpringApplication类的。这里必要分清楚,因为后续会使用RunListeners类直接调用SpringApplication里面的各种实例化出来的Listener类,跳出这个方法继续就到了listeners.starting();
方法,这里的listeners
是返回的SpringApplicationRunListeners类对象。
SpringApplicationRunListeners.starting
void starting() {
//由于listeners只有一个对象,这里循环了一个寂寞,估计Spring会在以后进行扩展
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
进入starting()
以后,发现这里对所有的SpringApplicationRunListener进行了一个循环,但是通过刚刚分析的代码知道这里其实就只有一个类对象EventPublishingRunListener的类对象。因此可以知道这里执行的就是EventPublishingRunListener.starting()
,跳转过去。
EventPublishingRunListener.starting
public void starting() {
// this.application就是上面的SpringApplication.class
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
进来以后发现里面的内容很少,但是却很重要,在拆解之前,要说明白这里传的是一个new ApplicationStartingEvent()
,也就是说给multicastEvent()
方法里面传递了一个ApplicationStarting事件。注意:这里就开始应用观察者模式了。拆解解释一下:
SimpleApplicationEventMulticaster
首先先说this.initialMulticaster
,它是SimpleApplicationEventMulticaster类对象,这个类从名字看大概知道是一个广播器,那么其实说明了EventPublishingRunListener并不是一个标准的Listener。其里面还有个广播器,会在这个类初始化的时候被new出来。这个过程十分的重要,因为在new出来广播器对象以后,Spring通过一个循环,把之前初始化好的所有监听器Listener都传递到了广播器中,这样广播器就可以对每个监听器进行响应。
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
//实例化广播器
this.initialMulticaster = new SimpleApplicationEventMulticaster();
//并且把之前拿到的ApplicationListener类全部循环加载到initialMulticaster对象里
// 这个广播器将会在后面根据event的不同进行不同的处理。换句话说根据event的类型循环使用不同的Listener进行处理
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
注解:
for循环以后initialMulticaster对象里面就有了下面的Listener类对象,一共11个
org.springframework.boot.ClearCachesApplicationListener,\ 1
org.springframework.boot.builder.ParentContextCloserApplicationListener,\ 2
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\ 3
org.springframework.boot.context.FileEncodingApplicationListener,\ 4
org.springframework.boot.context.config.AnsiOutputApplicationListener,\ 5
org.springframework.boot.context.config.ConfigFileApplicationListener,\ 6
org.springframework.boot.context.config.DelegatingApplicationListener,\ 7
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\ 8
org.springframework.boot.context.logging.LoggingApplicationListener,\ 9
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener 10
----分割,下面的在另一个文件里----
org.springframework.boot.autoconfigure.BackgroundPreinitializer 11
那么在执行starting()
的时候,就可以说this.initialMulticaster
已经把所有需要的监听器做了初始化,并存到了自己里面,所以this.initialMulticaster.multicastEvent(...)
所做的事情,就是把对应的事件发布出去。要注意的是这个方法已经脱离了SpringBoot的原始jar包,此时已经到了SpringFramework里的jar包中。
SimpleApplicationEventMulticaster. multicastEvent
注意这个方法的包名,是org.springframework.context,已经不是org.springframework.boot了。
org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(ApplicationEvent, ResolvableType)
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//使用多线程去执行监听器
Executor executor = getTaskExecutor();
//这里getApplicationListeners(event, type)是寻找对应的event和type是否对某个listener感兴趣
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
进入这个方法其实最重要的就是for
循环内容。最先说明一点,for
循环里面invokeListener(listener, event))
就是具体的Listener执行的内容,这点暂且不做分析,原因在前言部分已经说过了。这里重点分析的将会是Spring如何对某个事件感兴趣的,那么就直接进入getApplicationListeners(event, type)
。
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
//这里将会调用方法去找到是否有listener对传进来的东西感兴趣
Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// Quick check for existing entry on ConcurrentHashMap...
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
if (this.beanClassLoader == null ||
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
// Fully synchronized building and caching of a ListenerRetriever
synchronized (this.retrievalMutex) {
retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
retriever = new ListenerRetriever(true);
//最终将会使用这个方法去返回是否有对传递进来的事件event或者source感兴趣
Collection<ApplicationListener<?>> listeners =
retrieveApplicationListeners(eventType, sourceType, retriever);
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
}
else {
// No ListenerRetriever caching -> no synchronization necessary
//最终将会使用这个方法去返回是否有对传递进来的事件event或者source感兴趣
return retrieveApplicationListeners(eventType, sourceType, null);
}
}
进入以后略过各种初始化获取event
和cache
的部分,最终返回的是使用retrieveApplicationListeners()
方法拿到的结果,直接点进去。
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {
List<ApplicationListener<?>> allListeners = new ArrayList<>();
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
synchronized (this.retrievalMutex) {
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}//以上是做了一些初始化内容
//循环遍历listeners查看是否有感兴趣的监听器,如何判断呢,就是用GenericApplicationListener里面的两个方法去判断
for (ApplicationListener<?> listener : listeners) {
// 每个监听器都对同一个事件的进行过滤,直到发现一个合适的。
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
retriever.applicationListeners.add(listener);
}
allListeners.add(listener);
}
}
if (!listenerBeans.isEmpty()) {
/* 无关主线领略过
Add listeners by bean name, potentially overlapping with programmatically
registered listeners above - but here potentially with additional metadata.
*/
}
//排序
AnnotationAwareOrderComparator.sort(allListeners);
if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
retriever.applicationListeners.clear();
retriever.applicationListeners.addAll(allListeners);
}//返回所有感兴趣的Listeners
return allListeners;
}
可以看到最终判断是否对发的事件感兴趣主要是由条件语句中的supportsEvent()
方法的返回结果决定的。这个方法就是用来判断当前监听器对当前的事件是否感兴趣,可以看到这是一个for
循环,也就是说所有的监听器都会对同一个事件进行过滤,直到发现一个合适的。点入supportsEvent()
方法。
AbstractApplicationEventMulticaster.supportsEvent
protected boolean supportsEvent(
ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
// 类型转换
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
// 判断是否感兴趣
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
首先判断当前listener
是不是GenericApplicationListener。如果是直接用,如果不是转换成GenericApplicationListenerAdapter再用。因为GenericApplicationListener 是个接口,不能直接用的,除非外部实现了。然后根据GenericApplicationListener中的supportsEventType()
方法和supportsSourceType()
方法中的逻辑判断是否感兴趣。如果感兴趣,返回true
,如果不感兴趣,返回false
。
如何判断当前事件是否能引起某个Listener的兴趣
是否感兴趣是怎么判断得呢?其实从smartListener
对象调用supportsEventType()
和supportsSourceType()
方法就可以知道,每一个Listener里面都有实现这两个方法,如果Listener中对应得方法返回true
那就说明匹配上了,否则就是不感兴趣。这里一共要判断11次,不可能把每一个都拿出来讲一遍。所以返回出去那么getApplicationListeners(event, type)
这个方法就是所有对ApplicationStarting的事件感兴趣的监听器都添加到allListeners
列表里,并且作为一个for
循环的集合,在下面的方法里对所有在list里面的方法执行监听器应该做的事情,即执行对应的invokeListener(listener, event)
。
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//使用多线程去执行监听器
Executor executor = getTaskExecutor();
//这里getApplicationListeners(event, type)是寻找对应的event和type是否对某个listener感兴趣
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
最后一层一层点进去执行的就是ApplicationListener#onApplicationEvent()
方法,每一个监听器最终都会执行这个方法完成对应的逻辑。对这个方法感兴趣的同学可以去看【SpringBoot深度探究(六)事件编程模型(Listener-Event)的扩展】这篇博客。
总结
总结下本篇博客的内容,本篇说到SpringBoot启动了SpringApplicationRunListeners类,并且由这个类调用广播器对每一个Listener进行广播。如果一个Listener判断自己对某个类型(本篇只说了Strating后面还有会有别的类型)感兴趣,那么就添加到一个list里作为循环的集合。然后由外部for循环,循环调用Listener中的方法,进行具体的逻辑执行。随者SpringBoot的流程往下走,还会看到更多的事件被注册,以及更多的Listener执行,有兴趣的同学可以自己先读下。我们下一篇【SpringBoot深度探究(九)源码探究启动流程之三】将会说到SpringBoot在何处启动的Tomcat,最后在总结一下广播器的作用。
广播器initialMulticaster这个类的作用
1. 首先会广播一个事件,并且对询问所有的监听器是否感兴趣:
for (ApplicationListener<?> listener : getApplicationListeners(event, type))
在getApplicationListeners()传入了两个参数event,type,作为兴趣源或者事件类型。
这个方法的作用就是告诉所有的监听器,现在有了一个type类型的event,谁感兴趣?
2. 通知所有监听器
getApplicationListeners()里面会遍历所有的监听器,每一个监听器都会对这个方法进行判断,
是否对这个事件感兴趣。
如何判断呢?
a).用两个方法确定
supportsEventType(eventType)和supportsSourceType(sourceType),这两个方法
可以理解为通过传入一个事件类型到监听器里面,进而判断是否对这个事件感兴趣。如果感兴趣
返回true,如果不感兴趣返回false。如果是true会被添加到一个list中,再由后续的代码进行处理。
b).在监听器进行回调的时候
除了a)以外也可以通过onApplicationEvent(E event)进行判断,如果事件类型不感兴趣,那么不作
任何的处理即可。注:Spring是通过a)+b)进行双重判断的。
3. 获得所有对这个事件感兴趣的监听器以后,遍历执行onApplicationEvent(E event)方法。
这里的代码传递一个ApplicationStartingEvent的事件到里面去,最终决定如何执行相关的方法。
4. initialMulticaster金额图就阿布带事故SimpleApplicationEventMulticaster类型的对象
主要有两个方法,一个是广播事件,一个是执行listener的onApplicationEvent()方法。