run[1] - 配置引导流程
在上一部分中,我们已经分析了SpringApplication的构造方法。现在,我们来看看最重要的run方法。
在看源码之前,我们先想一想对于这个方法,我们调用的现象,和我们的预期是什么:
- 调用了这个方法之后,我们的应用就启动起来了
- 那么,这个方法,想来应该就是启动Spring应用的关键流程了。根据上面构造方法的分析,这里应该和listener和initializer是有相关联的。
那么接下来就来看看这些代码,这一次我们只看这一些:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
//....
}
开启了一个StopWatch,来监控启动时使用的时间。
随后开始构建一个DefaultBootstrapContext。
1.构建引导context
这里就遇到了Spring中第二个重要的概念:
- context
context顾名思义就是上下文。
根据我们开发的经验,上下文context这个变量的含义,基本上就包括了:
- 在开发过程中,我们需要的所有信息。
而bootStrap的意思是引导,在编程里一般都在初始化的过程里出现。
根据这一信息,我们也很好理解这一行代码为什么会出现在这里:
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
这个方法如下:
private DefaultBootstrapContext createBootstrapContext() {
DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
return bootstrapContext;
}
正如我们预测的一样
bootstrapRegistryInitializers
在后面排上用处了。
不过默认应用bootstrapRegistryInitializers,因此这里基本上啥都没做,这里也就不做深究。
回到主流程
在初始化引导上下文之后,声明了一个context变量,看起来这个应该就是我们在流程中使用的上下文对象了,不过这里是个null,我们就先按下不表,等用到的时候我们再看看具体的结构。
接下来流程中配置了一些系统变量:
2.configureHeadlessProperty
private void configureHeadlessProperty() {
System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}
这个东西和我们Spring服务没啥关系,不过说个题外话,这里的东西其实配置的是:
- java应用在缺失显示器等输入输出设备时,可以正常启动
这篇文章里说的很清楚了,网上的资料也很多,这里就不做过多赘述。
3.runListeners
接下来就拿出了我们当时设置的那些listener,并发布启动消息:
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
this.applicationStartup);
}
这里就看到了之前详细了解过的
getSpringFactoriesInstances
这里我们获取了runListener,通过我们的boosstrapContext,发布了启动消息。
这里的listener,都是一些基础级别的设施,比如:日志,文件编码等等,按下不表。
总结
至此我们分析了到run方法到try前进行的步骤,在解析中我们可以很清楚的看清楚:
-
这些步骤实际上并没有涉及到Spring的核心bean,只是做一些正式初始化前的准备工作,包括:
- 构建引导上下文
- 设置无输入输出设备时依然可以启动
- 通过监听者模式,发布了当前类start事件。
到此的知识合计
-
设计模式:
-
这里以及上一篇的构造方法,Spring中应用了如下这些设计模式:
-
监听器模式
-
这里明确地使用了监听者模式:
listeners.starting(bootstrapContext, this.mainApplicationClass); -
工厂模式:
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)这里通过类名和反射,构建了工厂实例。
-
-
-
核心知识涉及
-
到这里为止,出现过我们熟知的Spring核心类bean实际上比较少:
-
context
- DefaultBootstrapContext : 默认启动引导上下文
- ConfigurableApplicationContext : 这里只做了声明,实际上还是空的
\
-
-
-