Environment 的创建
从入口跟进 run 方法
java
@SpringBootApplication
public class MybatisPlusDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisPlusDemoApplication.class, args);
}
}
一直跟进到下面的 run 方法
在下面这个方法的这一行创建了 ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
java
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);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
/**
* 在这一行创建了 Environment
*/
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
跟进 prepareEnvironment 方法
在这一行代码,ConfigurableEnvironment environment = getOrCreateEnvironment(); 做了以下功能:
- 这里创建了一个 new ApplicationServletEnvironment(); 对象并返回,因为使用的是 Servlet 容器。
- 并且初始化了 systemProperties(存放 JVM 相关属性键值对) 和 systemEnvironment(存放用户电脑中环境变量相关的属性键值对) 两个属性集。
那 systemProperties 和 systemEnvironment 到底是怎么放在 Environment 中的呢?
- 首先,这里调用了 new ApplicationServletEnvironment();
- ApplicationServletEnvironment 继承了如下类,最终继承了 AbstractEnvironment 抽象类。
- extends ApplicationServletEnvironment
- extends StandardServletEnvironment
- extends StandardEnvironment
- extends AbstractEnvironment
- extends StandardEnvironment
- extends StandardServletEnvironment
- extends ApplicationServletEnvironment
- 由于 java 中,实例化对象时,默认必定先调用父类的无参构造函数(即使是抽象类,也会调用无参构造函数),因此,最终调用 AbstractEnvironment 的无参构造函数。
- 而在 AbstractEnvironment 的无参构造函数,会调用自身的 customizePropertySources 方法。
- 在 StandardEnvironment 中,由于重写了父类的方法,因此,调用到这个类中的 customizePropertySources 方法。
- 在 StandardEnvironment 中,就初始化了 systemProperties 和 systemEnvironment。
java
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// Create and configure the environment
/**
* 这里创建了一个 new ApplicationServletEnvironment(); 对象并返回。
* 因为使用的是 Servlet 容器。
* 并且初始化了 systemProperties(存放 JVM 相关属性键值对)
* 和 systemEnvironment(存放用户电脑中环境变量相关的属性键值对) 两个属性集。
*/
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 下面的看起来好像做了些什么事,实际上没多大作用
configureEnvironment(environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach(environment);
/**
* 这里往 Environment 中又分别添加了 application.yaml 和 application-dev.yaml的配置。
* 并设置了 profiles(默认=dev)
*/
listeners.environmentPrepared(bootstrapContext, environment);
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}