此篇文章继续解析SpringApplication的run
方法具体代码如下:
public ConfigurableApplicationContext run(String... args) {
1.StopWatch stopWatch = new StopWatch();
2.stopWatch.start();
3.ConfigurableApplicationContext context = null;
4.Collection exceptionReporters = new ArrayList<>();
5.configureHeadlessProperty();
6.SpringApplicationRunListeners listeners = getRunListeners(args);
7.listeners.starting();
try {
8. ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
9. ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
10. configureIgnoreBeanInfo(environment);
11. Banner printedBanner = printBanner(environment);
12. context = createApplicationContext();
13. exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
14. prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
15. refreshContext(context);
16. afterRefresh(context, applicationArguments);
17. stopWatch.stop();
18. if (this.logStartupInfo) {
19. new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
20. listeners.started(context);
21. callRunners(context, applicationArguments);
}
catch (Throwable ex) {
22. handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
23. listeners.running(context);
}
catch (Throwable ex) {
24. handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
一共24行代码,本章主要解析8-11小节。
ApplicationArguments
- 当我们把springboot 打包成jar包运行的时候输入jar -jar test.jar --debug test.log,则我们通过ApplicationArguments 获取到的参数就是"--debug test.log",而ApplicationArguments 可以将这些参数转化成key和value形式
ConfigurableEnvironment
这边创建我们的运行时候环境
private ConfigurableEnvironment getOrCreateEnvironment() {
如果我们自己设置了environment,则直接使用
if (this.environment != null) {
return this.environment;
}
否则根据webApplicationType 选择合适的webApplicationType
if (this.webApplicationType == WebApplicationType.SERVLET) {
return new StandardServletEnvironment();
}
return new StandardEnvironment();
}
根据@Profile和spring.profiles.active=xxx 可以在不同的情况下初始化不同的类,但是我们一般都采用这种方式来隔离线上和线下环境
protected void configureEnvironment(ConfigurableEnvironment environment,
String[] args) {
将参数和一些默认的属性配置到environment
configurePropertySources(environment, args);
激活profile
configureProfiles(environment, args);
}
调用SpringApplicationRunListener的environmentPrepared方法,我们在这里面更新了我environent的配置PropertySource,可以看到我们在这里吗通过监听其设置我们的一些propertysource的具体文位置,或者设置具体的对象(主要是通过ConfigFileApplicationListener)
比如StandardServletEnvironment {activeProfiles=[], defaultProfiles=[default],
-
- propertySources=[StubPropertySource {name='servletConfigInitParams'}, StubPropertySource
2.{name='servletContextInitParams'}, MapPropertySource {name='systemProperties'},
-3.OriginAwareSystemEnvironmentPropertySource {name='systemEnvironment'},
4.RandomValuePropertySource {name='random'},
-
- OriginTrackedMapPropertySource {name='applicationConfig: [classpath:/application.properties]'}]}
public void environmentPrepared(ConfigurableEnvironment environment) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.environmentPrepared(environment);
}
}
就是把SpringApplication和"spring.main"绑定放入environment对应的Binder
protected void bindToSpringApplication(ConfigurableEnvironment environment) {
try {
Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));
}
catch (Exception ex) {
throw new IllegalStateException("Cannot bind to SpringApplication", ex);
}
}
如果webApplicationType是为none 则创建一个EnvironmentConverter 并且转化成StandardEnvironment
if (this.webApplicationType == WebApplicationType.NONE) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
ConfigurationPropertySources.attach(environment);
从environment获取MutablePropertySources ,然后删除若已经存在的属性configurationProperties,然后创建一个ConfigurationPropertySourcesPropertySource,其内部把属性configurationProperties设置为对应的SpringConfigurationPropertySources
- 这边的两个类还不清楚专门干嘛的SpringConfigurationPropertySources和ConfigurationPropertySourcesPropertySource
public static void attach(Environment environment) {
Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
MutablePropertySources sources = ((ConfigurableEnvironment) environment)
.getPropertySources();
PropertySource> attached = sources.get(ATTACHED_PROPERTY_SOURCE_NAME);
if (attached != null && attached.getSource() != sources) {
sources.remove(ATTACHED_PROPERTY_SOURCE_NAME);
attached = null;
}
if (attached == null) {
sources.addFirst(new ConfigurationPropertySourcesPropertySource(
ATTACHED_PROPERTY_SOURCE_NAME,
new SpringConfigurationPropertySources(sources)));
}
}
设置spring.beaninfo.ignore的属性,以及打印Banner
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
- PropertySources:一个接口提供了对PropertySource的迭代操作
- PropertySource:是一个容器里面存储了各个source(每个source有一个对应的名字)
- ConfigurationPropertySourcesPropertySource继承了PropertySource且实现了OriginLookup(可以寻找)
其中ConfigurationPropertySourcesPropertySource的source是ConfigurationPropertySource
我们在这边塞入的SpringConfigurationPropertySources就是其一个子类