我的想写《springboot源码解析》这一系列好久了,可是一直角儿心底的知识积累不足,因此一直没有动笔。html
因此想找一些小伙伴一块儿写这一系列,互相纠错交流学习。java
若是有小伙伴有兴趣一块儿把这一系列的讲解写完的话,加下我微信:13670426148,咱们一块儿完成,当交流学习。web
后期还想写一系列介绍rpc框架的,不过要再过一阵子了,先把springboot的写完,坚持一周一更,周末更新spring
上篇回顾 讲了SpringApplication的实例化,其中最主要的是加载Spring的Listener和Initializer,Listener为10个,Initializer为6个,详细查看 走心Springboot源码解析: 1、SpringApplication的实例化缓存
上篇写完以后才发现以前用的是springboot1.5的版本,可是如今你们都是用springboot2.+,因此我找了个springboot2.0+ 的项目来进行解析,可是第一篇就还没改变,到时候有空再更新,不过大体的内容仍是差很少的。springboot
这篇主要讲run()方法,分红两部分,这篇先讲上半部分,主要聚焦在run()方法中涉及到的 事件-监听器-广播 机制,直到建立上下文部分(context = this.createApplicationContext())。bash
public ConfigurableApplicationContext run(String... args) {
//这是一个计时器,stopWatch.start()开始计时,到后面stopWatch.stop()中止计时。
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//这个ConfigurableApplicationContext就是咱们说的 上下文,后面preContext()的时候会详细解析,这个是springboot中最重要的一个类了
ConfigurableApplicationContext context = null;
//自定义SpringApplication启动错误的回调接口
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
//此为设置 System 里面有一个properties的里的值 "java.awt.headless" ,设置为默认值true
this.configureHeadlessProperty();
//这个SpringApplicationRunListeners可跟前面的10个Listener不同,这里面封装了一个广播。后面会讲他的实例化过程
SpringApplicationRunListeners listeners = this.getRunListeners(args);
//开始进行事件广播,下面详细解析
listeners.starting();
Collection exceptionReporters;
try {
//获取初始化参数,就是咱们运行时的初始化参数,好比“java -jar --port=8080” 其中port就是一个参数了
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//environment是运行时环境
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
//打印出springboot的标志,这个能够本身选择要打印输出的文本.
Banner printedBanner = this.printBanner(environment);
//建立根上下文,这个方法特别重要,将是下章讲解的重点
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
//准备环境,下面先不讲了。
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 var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
复制代码
SpringApplicationRunListeners:一个存SpringApplicationRunListener的集合,里面有些方法,后续都会讲到;微信
SpringApplicationRunListeners :
| SpringApplicationRunListener
|SimpleApplicationEventMulticaster
SimpleApplicationEventMulticaster
才是真正的广播,SpringApplicationRunListeners只不过是对其的一层封装
复制代码
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
//这里就不赘述了,META-INF/spring.factories下
//1. 获取key为SpringApplicationRunListener类路径为key 对应的 value
//2. 实例化value对应的类,最后获得的类是EventPublishingRunListener.class,,如图1.1所示
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
复制代码
图1.1: app
从命名咱们就能够知道它是一个监听者,那纵观整个启动流程咱们会发现,它实际上是用来在整个启动流程中接收不一样执行点事件通知的监听者,SpringApplicationRunListener接口规定了SpringBoot的生命周期,在各个生命周期广播相应的事件,调用实际的ApplicationListener类。 接下来看SpringApplicationRunListener SpringApplicationRunListener接口规定了SpringBoot的生命周期框架
public class SpringApplicationRunListener{
//刚执行run方法时
void started();
//环境创建好时候
void environmentPrepared(ConfigurableEnvironment environment);
//上下文创建好的时候
void contextPrepared(ConfigurableApplicationContext context);
//上下文载入配置时候
void contextLoaded(ConfigurableApplicationContext context);
//上下文刷新完成后,run方法执行完以前
void finished(ConfigurableApplicationContext context, Throwable exception);
}
复制代码
它定义了5个步骤:
咱们来看EventPublishingRunListener的构造器。还有他的两个重要的方法:
EventPublishingRunListener类 实现了SpringApplicationRunListener,它具备广播事件的功能。
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
//这个是参数传进来的,也就是SpringApplication.class
private final SpringApplication application;
//这个是初始化参数
private final String[] args;
//真正的广 播
private final SimpleApplicationEventMulticaster initialMulticaster;
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
//新创建广播器,这个广播器特别重要,下面继续解析
this.initialMulticaster = new SimpleApplicationEventMulticaster();
//application.getListeners()就是获取10个初始化的Listenter,具体能够参见上一篇了解哪10个Listener
Iterator var3 = application.getListeners().iterator();
while(var3.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var3.next();
//添加到内部的defaultRetriever里,详细代码能够本身翻进去查看,这里不拓展,
//后面须要根据事件类型推测有哪些监听器须要被触发,因此就得存把全部的监听器先存起来,称做一个注册表吧
this.initialMulticaster.addApplicationListener(listener);
}
}
}
复制代码
就是说,EventPublishingRunListener里面有一个广播器,结合上面的SpringApplicationRunListener接口声明的方法,咱们能够获得其机制大概是:
multicastEvent() 方法就是广播方法 SimpleApplicationEventMulticaster广播出去,广播出去的事件对象会被SpringApplication中的listeners属性进行处理。
下面先解析一下广播方法multicastEvent() 和 执行方法 invokeListener()
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
//去注册表中根据相应的事件,获取Event对应的Listener。后面会简略讲讲获取的过程
Iterator var4 = this.getApplicationListeners(event, type).iterator();
while(var4.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var4.next();
Executor executor = this.getTaskExecutor();
if (executor != null) {
executor.execute(() -> {
this.invokeListener(listener, event);
});
} else {
//最后的执行方法是这个,参数是“监听器和事件”
this.invokeListener(listener, event);
}
}
}
//执行方法
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = this.getErrorHandler();
if (errorHandler != null) {
try {
//看多了源码大家会发现,spring的源码很喜欢这么写,通常invokeListener的时候不是真的invokeListener的真实过程
//而是会把真正的逻辑放到 doInvokeListener(do****,这里就是doInvokeListener)中执行.
//1. 而在invokeListener中只是在真正处理方法前作一点数据封装,
//2. 或者异常检查
// 目的:我的感受主要的目的是把真正处理过程的代码缩减,使得真正的处理逻辑变得简洁易懂,不会有多余的代码加剧理解难度
this.doInvokeListener(listener, event);
} catch (Throwable var5) {
errorHandler.handleError(var5);
}
} else {
this.doInvokeListener(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.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, var6);
}
}
}
复制代码
因此总结一下 两种监听器和广播器的关系以下: SpringApplicationRunListeners、SpringApplicationRunListener、SimpleApplicationEventMulticaster
(1) SpringApplicationRunListeners是SpringApplicationRunListener的封装。pringApplicationRunListeners中包含多个SpringApplicationRunListener, 是为了批量执行的封装,SpringApplicationRunListeners与SpringApplicationRunListener生命周期相同,调用每一个周期的各个SpringApplicationRunListener 而后广播利用SimpleApplicationEventMulticaster进行广播。
(2)SimpleApplicationEventMulticaster是封装在SpringApplicationRunListener里面的广播器,
经过上面的3个特色能够看出SpringApplicationRunListener。springboot启动的几个主要过程的监听通知都是经过他来进行回调。 流程图如图1.2所示
直接把代码看到listeners.starting()
这一行
class SpringApplicationRunListeners {
public void starting() {
//这里获取SpringApplicationRunListeners里面的List<SpringApplicationRunListener>
Iterator var1 = this.listeners.iterator();
//通常状况下,他只是一个,虽然这里是个list,因此这个while里面只会走1次
while(var1.hasNext()) {
SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();
//这个就进去到SpringApplicationRunListener里面去了,而此时SpringApplicationRunListener的实现类是EventPublishingRunListener
listener.starting();
}
}
}
/** ** EventPublishingRunListener实现了SpringApplicationRunListener,因此就得实现里面的starting(), environmentPrepared()等,贯穿整个springboot启动流程,而starting()只是他其中最开始的一步,看最上面总体的代码部分就知道了,后面还有environmentPrepared(), contextPrepared()等 **/
pubic class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
public void starting() {
//1. 广播器执行广播事件方法
//2. 参数是包装出来的 ApplicationStartingEvent ,跟下面的environmentPrepared,contextPrepared方法比,他们的事件都类型都不一样的
//(1) starting对应的是ApplicationStartingEvent
//(2) environmentPrepared对应的是 ApplicationEnvironmentPreparedEvent
//(3) ApplicationContextInitializedEvent对应的是 ApplicationContextInitializedEvent
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
}
public void contextPrepared(ConfigurableApplicationContext context) {
this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}
//省略****
}
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
//开始进行广播方法,由于此时是staring()方法出发的,因此这里的envent是在EventPublishingRunListener中new ApplicationContextInitializedEvent,
public void multicastEvent(ApplicationEvent event) {
//1. 第二个参数推断出eventType,,在真正执行广播
this.multicastEvent(event, this.resolveDefaultEventType(event));
}
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) { //推断出类型
ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
//从注册表中根据event类型,得到全部对应的监听器,
//结果得到的全部监听器有:
//(1) LoggingApplicationListener、
//(2) BackgroundPreinitializer、
//(3) DelegatingApplicationListener
//(4) LiquibaseServiceLocatorApplicationListener
//(5)EnableEncryptablePropertiesBeanFactoryPostProcessor
//五种类型的对象。这五个对象的onApplicationEvent都会被调用。
Iterator var4 = this.getApplicationListeners(event, type).iterator();
while(var4.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var4.next();
Executor executor = this.getTaskExecutor();
if (executor != null) {
executor.execute(() -> {
this.invokeListener(listener, event);
});
} else {
//直接看调用方法
this.invokeListener(listener, event);
}
}
}
//这就是最终的调用点,Listener的onApplicationEvent(ApplicationEvent) 方法。
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.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, var6);
}
}
}
}
复制代码
那么这五个监听器的onApplicationEvent都作了些什么了,我这里大概说下,细节的话你们自行去跟源码。
(1) LoggingApplicationListener:初始化日志系统,默认是logback,支持3种,优先级从高到低:logback > log4j > javalog
(2) BackgroundPreinitializer:启动多个线程执行相应的任务,包括验证器、消息转换器等等
(3) DelegatingApplicationListener:此时什么也没作
(4) LiquibaseServiceLocatorApplicationListener:此时什么也没作
(5)EnableEncryptablePropertiesBeanFactoryPostProcessor:仅仅打印了一句日志,其余什么也没作 对了,补充一点注册器的代码 喜欢就看,不喜欢就跳过,
// 返回全部的适合于ApplicationStartedEvent的监听器集合
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
Object source = event.getSource();
Class<?> sourceType = source != null ? source.getClass() : null;
//根据eventType和sourceType组装一个key便是cacheKey
AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType);
//retriever里面包装了全部适合的监听器。
AbstractApplicationEventMulticaster.ListenerRetriever retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey);
//下面是双通道机制的单例模式写法,直接看标注注释的那行代码便可
if (retriever != null) {
return retriever.getApplicationListeners();
} else if (this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader))) {
synchronized(this.retrievalMutex) {
retriever = (AbstractApplicationEventMulticaster.ListenerRetriever)this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
} else {
//当第一次执行的时候,建立一个 retriever,
retriever = new AbstractApplicationEventMulticaster.ListenerRetriever(true);
//下面进行详细解析;
//直接在这里获取全部适合于ApplicationStartedEvent的监听器集合,并使用retriever.applicationListeners.add(listener);,添加到retriever中,
Collection<ApplicationListener<?>> listeners = this.retrieveApplicationListeners(eventType, sourceType, retriever);
//以cacheKey为key,存到缓存中。
this.retrieverCache.put(cacheKey, retriever);
//返回全部的适合于ApplicationStartedEvent的监听器集合
return listeners;
}
}
} else {
return this.retrieveApplicationListeners(eventType, sourceType, (AbstractApplicationEventMulticaster.ListenerRetriever)null);
}
}
//上面方法的解析,直接在这里获取全部适合于ApplicationStartedEvent的监听器集合。
private Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable
AbstractApplicationEventMulticaster.ListenerRetriever retriever) {
List<ApplicationListener<?>> allListeners = new ArrayList();
LinkedHashSet listeners;
LinkedHashSet listenerBeans;
synchronized(this.retrievalMutex) {
//this.defaultRetriever.applicationListeners是全部默认的监听器,就是那10个默认的监听器,以下图所示
listeners = new LinkedHashSet(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans);
}
Iterator var7 = listeners.iterator();
while(var7.hasNext()) {
ApplicationListener<?> listener = (ApplicationListener)var7.next();
//就是在这里进行判断的,具体怎么判断就不进去了,这个不是重点
if (this.supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
retriever.applicationListeners.add(listener);
}
allListeners.add(listener);
}
}
//........篇幅有限,这个其实不重要,直接略过便可
}
复制代码
//todo: 这部分能够用“监听器-事件-广播” 解释一下,下周末有时间再进行补充。 prepareEnvironment(listeners, applicationArguments);
加载SpringBoot配置环境(configurableEnvironment),若是是经过web容器发布,会加载StandardEnvironment。将配置文件(Environment)加入到监听器对象中(SpringApplicationRunListeners)
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
// Create and configure the environment
//若是environment不为空直接返回 || 若是是web环境则直接实例化StandardServletEnvironment类 || 若是不是web环境则直接实例化StandardEnvironment类
ConfigurableEnvironment environment = getOrCreateEnvironment();
//配置环境信息
configureEnvironment(environment, applicationArguments.getSourceArgs());
//通知全部的监听者,环境已经准备好了
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
复制代码
本篇主要讲了“监听器-事件-广播”的涉及到的几个类,展现了一个周期 starting()的运行过程。 再总结一下,流程以下:
下期打算讲一讲, context的部分,这个内容就有不少了啊。。
参考内容: 大神写的,分析很透彻,站在巨人的肩膀上: