前置知识:
一、什么是SPI以及spring.factories文件的加载解析流程
什么是SPI?
SPI ,全称为 Service Provider Interface,是一种服务发现机制。它通过在ClassPath路径下的
META-INF/services
文件夹查找文件,自动加载文件里所定义的类。这一机制为很多框架扩展提供了可能,比如在Dubbo、JDBC中都使用到了SPI机制。
什么是SpringFactoriesLoader?
它其实和java中的SPI机制的原理是一样的,不过它比SPI更好的点在于不会一次性加载所有的类,而是根据key进行加载。
首先,SpringFactoriesLoader的作用是从classpath/META-INF/spring.factories文件中,根据key来加载对应的类到spring IoC容器中。
spring.factories介绍
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));这个方法是解析该文件的入口,在springboot中,需要获取spring.factories文件中的实例对象了调这个方法,先读取names再createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);通过反射生成。
在springBoot项目启动的过程中需要用到两个名称为spring.factories的文件,该文件存在于
org\springframework\boot\spring-boot\2.2.2.RELEASE\spring-boot-2.2.2.RELEASE.jar!\META-INF\spring.factories
和org\springframework\boot\spring-boot-autoconfigure\2.2.2.RELEASE\spring-boot-autoconfigure-2.2.2.RELEASE.jar!\META-INF\spring.factories
这个文件内部存的是一个K-V键值对,内容如下:
spring-boot-2.2.2.RELEASE.jar:
# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader
spring-boot-autoconfigure-2.2.2.RELEASE.jar:
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
上面两个文件的加载解析到内存的堆栈调用路径如下:
在SpringApplication 的构造方法中
loadSpringFactories:133, SpringFactoriesLoader (org.springframework.core.io.support)
loadFactoryNames:122, SpringFactoriesLoader (org.springframework.core.io.support)
getSpringFactoriesInstances:490, SpringApplication (org.springframework.boot)
getSpringFactoriesInstances:473, SpringApplication (org.springframework.boot)
<init>:278, SpringApplication (org.springframework.boot)
<init>:254, SpringApplication (org.springframework.boot)
run:1299, SpringApplication (org.springframework.boot)
run:1285, SpringApplication (org.springframework.boot)
main:15, StartApp (com.bobo.demo)
ApplicationContextInitializer.class和ApplicationListener.class在上面两个spring.factories文件都能找到对应的类的全限定名:
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
然后将这些类实例化进行构造函数成员变量赋值。
loadFactoryNames:从“META-INFspring”中加载给定类型的工厂实现的完全限定类名。工厂”,使用给定的类装入器
从上可以看到org.springframework.context.ApplicationContextInitializer对应的有7个,直接一次将META-INF/spring.factories所有值加载,后续直接根据key获取即可。该方法返回names然后进行实例化,后续所有此操作都一样。
二、SpringBoot中监听器的加载和执行流程、发布事件的执行源码分析
1、上面在SpringApplication的构造方法中有初始化监听器,方法如下:
// 初始化监听器 并将加载的监听器实例对象存储在了listeners成员变量中
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
通过上文分析可知,读取spring.factories文件获取到ApplicationListener对应的类路径为:
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
共计11个,这些是内置的监听器,后续发布事件由这些监听器执行onApplicationEvent方法,前提条件是方法的event和发布的事件一致才行。
2、内置的事件触发器
run:331, SpringApplication (org.springframework.boot)
run:1299, SpringApplication (org.springframework.boot)
run:1285, SpringApplication (org.springframework.boot)
main:15, StartApp (com.bobo.demo)
重点看SpringApplicationRunListeners listeners = getRunListeners(args);方法:
getRunListeners实现:
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
// getSpringFactoriesInstances 读取spring.factories 文件中key 为 SpringApplicationRunListener 类型的
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
spring.factories文件显示的类路径:
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
SpringApplicationRunListener的实现类是EventPublishingRunListener从文件可以看出
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)会完成实例化操作
这里的参数对应EventPublishingRunListener构造函数的参数:
在SpringApplication构造函数中实例化了11个监听器,这里又把SpringApplication对象的监听器放到EventPublishingRunListener的成员变量initialMulticaster中,后续执行监听事件就是用它。至此,监听器和EventPublishingRunListener绑定在一起,EventPublishingRunListener可以理解为广播器。下面开始讲解监听事件的执行流程:
listeners.starting();开始触发事件
List listeners只有一个实例,
可以看到这里发布的事件是ApplicationStartingEvent,继承自SpringApplicationEvent以及发布事件的类图
最终执行的是multicastEvent方法,getApplicationListeners(event, type)会返回所有监听了ApplicationStartingEvent事件的监听器,然后用来遍历执行监听器的onApplicationEvent方法。每个监听器的onApplicationEvent实现的细节不同。
getApplicationListeners实现细节如下:
retrieveApplicationListeners:281, AbstractApplicationEventMulticaster (org.springframework.context.event)
getApplicationListeners:197, AbstractApplicationEventMulticaster (org.springframework.context.event)
multicastEvent:134, SimpleApplicationEventMulticaster (org.springframework.context.event)
multicastEvent:127, SimpleApplicationEventMulticaster (org.springframework.context.event)
starting:75, EventPublishingRunListener (org.springframework.boot.context.event)
starting:49, SpringApplicationRunListeners (org.springframework.boot)
run:333, SpringApplication (org.springframework.boot)
run:1299, SpringApplication (org.springframework.boot)
run:1285, SpringApplication (org.springframework.boot)
main:15, StartApp (com.bobo.demo)
retrieveApplicationListeners返回监听该事件的监听器:
LoggingApplicationListener 这个监听器的执行堆栈:
onApplicationStartingEvent:239, LoggingApplicationListener (org.springframework.boot.context.logging)
onApplicationEvent:220, LoggingApplicationListener (org.springframework.boot.context.logging)
doInvokeListener:172, SimpleApplicationEventMulticaster (org.springframework.context.event)
invokeListener:165, SimpleApplicationEventMulticaster (org.springframework.context.event)
multicastEvent:139, SimpleApplicationEventMulticaster (org.springframework.context.event)
multicastEvent:127, SimpleApplicationEventMulticaster (org.springframework.context.event)
starting:75, EventPublishingRunListener (org.springframework.boot.context.event)
starting:49, SpringApplicationRunListeners (org.springframework.boot)
run:333, SpringApplication (org.springframework.boot)
run:1299, SpringApplication (org.springframework.boot)
run:1285, SpringApplication (org.springframework.boot)
main:15, StartApp (com.bobo.demo)
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationStartingEvent) {
onApplicationStartingEvent((ApplicationStartingEvent) event);
}
else if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
}
else if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent((ApplicationPreparedEvent) event);
}
else if (event instanceof ContextClosedEvent
&& ((ContextClosedEvent) event).getApplicationContext().getParent() == null) {
onContextClosedEvent();
}
else if (event instanceof ApplicationFailedEvent) {
onApplicationFailedEvent();
}
}
然后执行onApplicationStartingEvent((ApplicationStartingEvent) event);:
LoggingApplicationListener 执行之后,继续遍历其他的监听器的onApplicationEvent方法,完成
// 触发启动事件 发布 starting 事件 --》 那么监听starting事件的监听器就会触发
listeners.starting();
.listeners.starting();就讲完了,后续其他的事件也都是这个流程,逐步分析即可。