SpringBoot启动流程:创建Environment

Environment组成

首先,Environment是Spring3.1才提供的一个接口。它是对当前运行的应用程序的环境的抽象,下面我们了解一下它的组成。
先看下uml类图:
SpringBoot启动流程:创建Environment_第1张图片

Environment由两部分组成

1)profiles

profile中文直译是"概述"、“简介”、"轮廓"的意思,但在使用spring开发应用程序的时候,我们对profile的认识更亲切的是用在划分多环境的时候。

通常,我们会将profile划分成如:开发、测试、预生产、生产环境。每个环境会有有些bean不同、配置不同等。每个profile将有相应的bean和配置与之匹配,那么当我们切换profile的时候自然也就切换了相应的bean和配置文件,从而达到在不同环境中快速切换避免不断修改的问题。

这也就是spring的java doc里面描述的"logical group"的意思。

2)properties

properties的概念想必我们已经非常熟悉了,在java中properties代表着key-value的键值对象集合。而Environment中的properties不同,它内部定义了一个name表示文件的名字,一个泛型source(可以理解为一个Map)内部是key-value结构的对象来存储相应的键值。
下面是PropertySource的源码

public abstract class PropertySource<T> {
     

    protected final String name;

    protected final T source;

    // 省略
}

看起来就是一个key-value的数据结构是吗?这里请注意!跟我们想象的稍微有点不同,举例说明

我们创建了一个config.properties文件,内容如

username=test
password=a123456

那么当config.properties这个文件被加载到内存中,并作为一个PropertySource存在的时候,name=config而非name=username或者password。也就是说,加载config.properties这样的资源,泛型T将会是一个Map集合,而Map集合包含着config.properties文件中所有的键值对。

另外,我们注意到PropertySource是一个抽象类。spring将会针对资源的不同来源而使用不同的实现,例如上例中的config.properties加载到内存作为Properties对象添加的,就是PropertySource的其中一个实现类PropertiesPropertySource。
综上所述,Environment中包含着用于切换环境的profile,还包含着存储键值对的properties。

prepareEnvironment创建Environment

创建Environment的主要逻辑代码

private ConfigurableEnvironment prepareEnvironment(
        SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments
        ) {
     
    // 创建一个Environment对象
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    // 配置Environment对象
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    // 触发监听器(主要是触发ConfigFileApplicationListener,这个监听器将会加载如application.properties/yml这样的配置文件)
    listeners.environmentPrepared(environment);
    bindToSpringApplication(environment);
    if (!this.isCustomEnvironment) {
     
        environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
                deduceEnvironmentClass());
    }
    ConfigurationPropertySources.attach(environment);
    return environment;
}

该方法核心内容包括三部分

1)创建一个Environment对象

2)配置Environment对象

3)触发ConfigFileApplicationListener监听器(加载application.properties/yml将再后续文章中说明)

getOrCreateEnvironment()
我们跟进getOrCreateEnvironment方法看看创建过程

private ConfigurableEnvironment getOrCreateEnvironment() {
     
    if (this.environment != null) {
     
        return this.environment;
    }
    switch (this.webApplicationType) {
     
    case SERVLET:
        return new StandardServletEnvironment();
    case REACTIVE:
        return new StandardReactiveWebEnvironment();
    default:
        return new StandardEnvironment();
    }
}

在第一篇文章中,我们提到SpringApplication在deduceFromClassPath方法中会推断出WebApplicationType具体的枚举实例,代表了当前应用的类型。

getOrCreateEnvironment方法中根据WebApplicationType类型选择具体的Environment类型,也就是我们提到过的Servlet类型、Reative类型或者非Web应用类型。

configureEnvironment()

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
     
    if (this.addConversionService) {
     
        ConversionService conversionService = ApplicationConversionService.getSharedInstance();
        environment.setConversionService((ConfigurableConversionService) conversionService);
    }
    // 添加初始的properties(注意:当前并未加载如application.properties/yml的properties)
    configurePropertySources(environment, args);
    // 添加初始的profile(注意:当前并未加载如application.properties/yml配置profile)
    configureProfiles(environment, args);
}

总结

到这里,我们大体地讲解了Environment的接口设计、profile和properties的数据结构设计。再从prepareEnvironment方法中看到了Environment是根据webApplicationType匹配后创建的。到这里,Environment相关的内容简单介绍就结束了,我们也初步地为spring地Context创建了一个Environment的对象。

写的比较详细:https://www.cnblogs.com/lay2017/p/11483943.html

你可能感兴趣的:(spring源码,springboot启动流程)