Skip to content

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
  • 由于 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;
}