美文网首页
06--SpringBoot启动之环境初始化

06--SpringBoot启动之环境初始化

作者: 闲来也无事 | 来源:发表于2018-08-20 22:17 被阅读134次

假如有开发,测试,生产三个不同的环境,需要定义三个不同环境下的配置,以properties配置为例,在SpringBoot中会存在下列配置文件

  • applcation.properties
  • application-dev.properties
  • application-test.properties
  • application-online.properties
    那么SpringBoot是如何知道加载哪个配置文件呢,答案就在SpringBoot环境初始化,也是今天要分析的内容,继续run方法
//创建ApplicationArguments对象,并将args封装至对象实例
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

//创建并配置环境
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
    // Create and configure the environment
    // 获取或创建环境
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    // 配置环境
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    // 事件广播...这段代码应该很熟悉了吧...
    listeners.environmentPrepared(environment);
    // 将环境绑定到SpringApplication
    bindToSpringApplication(environment);
    // 如果当前环境是NONE,则
    if (this.webApplicationType == WebApplicationType.NONE) {
        environment = new EnvironmentConverter(getClassLoader()).convertToStandardEnvironmentIfNecessary(environment);
    }
    ConfigurationPropertySources.attach(environment);
    return environment;
}

可以看到,环境初始化包含了两个步骤,创建配置,逐个分析

1.环境初始化-创建环境

//获取或创建环境
private ConfigurableEnvironment getOrCreateEnvironment() {
    //当前环境不为空,直接返回
    if (this.environment != null) {
        return this.environment;
    }
    //当前应用类型为SERVLET,创建StandardServletEnvironment
    if (this.webApplicationType == WebApplicationType.SERVLET) {
        return new StandardServletEnvironment();
    }
    //否则创建StandardEnvironment
    return new StandardEnvironment();
}

当前分析的代码类型为WebApplicationType.NONE,我们以new StandardEnvironment()为例进行分析是如何创建环境的,在此之前,先来看下StandardEnvironment类的类继承结构

image.png

有了类继承关系,就可通过Debug代码,查看new StandardEnvironment()时具体初始化了哪些东西

1.1 StandardEnvironment
/** System environment property source name: {@value}. */
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";

/** JVM system properties property source name: {@value}. */
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
1.2 抽象父类AbstractEnvironment
private final Set<String> defaultProfiles = new LinkedHashSet<>(getReservedDefaultProfiles());

protected Set<String> getReservedDefaultProfiles() {
    return Collections.singleton(RESERVED_DEFAULT_PROFILE_NAME);
}
// 其中有几个常量大家可以预先熟悉下,有助于下面代码分析
// 这个常量大家一定熟悉了,profile的激活配置
public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active";
// 可用在web.xml中
//<context-param>
   //<param-name>spring.profiles.default</param-name>
   //<param-value>development</param-value>
//</context-param>
public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profiles.default";
// 默认节点名,SpringBoot启动控制台的
// No active profile set, falling back to default profiles: default这句话大家一定不陌生了
protected static final String RESERVED_DEFAULT_PROFILE_NAME = "default";
// 会保存获取到的激活的profile节点信息
private final Set<String> activeProfiles = new LinkedHashSet<>();

看到RESERVED_DEFAULT_PROFILE_NAME大家应该明白了,如果不指定profile节点,那么SpringBoot默认选择的是default节点

2.环境初始化-配置环境

// 配置环境
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
    // 配置PropertySources
    configurePropertySources(environment, args);
    // 配置Profiles节点
    configureProfiles(environment, args);
}

逐步分析

2.1 配置PropertySources

protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
    MutablePropertySources sources = environment.getPropertySources();
    if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
        sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties));
    }
    if (this.addCommandLineProperties && args.length > 0) {
        String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
        if (sources.contains(name)) {
            PropertySource<?> source = sources.get(name);
            CompositePropertySource composite = new CompositePropertySource(name);
            composite.addPropertySource(new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
            composite.addPropertySource(source);
            sources.replace(name, composite);
        } else {
            sources.addFirst(new SimpleCommandLinePropertySource(args));
        }
    }
}

2.2 配置Profiles节点

// 配置Profiles节点
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
    // 确保节点已被初始化
    environment.getActiveProfiles();
    Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles);
    profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
    // 激活profile节点
    environment.setActiveProfiles(StringUtils.toStringArray(profiles));
}
#################################getActiveProfiles()#################################
// 从当前环境中获取被激活的profile节点
public String[] getActiveProfiles() {
    return StringUtils.toStringArray(doGetActiveProfiles());
}

// 从当前环境中获取被激活的profile节点
protected Set<String> doGetActiveProfiles() {
    synchronized (this.activeProfiles) {
        if (this.activeProfiles.isEmpty()) {
            // ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active";
            // 本例并未指定spring.profiles.active属性,所以这里获取到的是null
            String profiles = getProperty(ACTIVE_PROFILES_PROPERTY_NAME);
            if (StringUtils.hasText(profiles)) {
                setActiveProfiles(StringUtils.commaDelimitedListToStringArray(
                        StringUtils.trimAllWhitespace(profiles)));
            }
        }
        return this.activeProfiles;
    }
}

public String getProperty(String key) {
    return this.propertyResolver.getProperty(key);
}

public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active";


#################################setActiveProfiles()#################################
// 这段代码很简单了,把激活的profile节点放入activeProfiles集合
public void setActiveProfiles(String... profiles) {
    Assert.notNull(profiles, "Profile array must not be null");
    if (logger.isDebugEnabled()) {
        logger.debug("Activating profiles " + Arrays.asList(profiles));
    }
    synchronized (this.activeProfiles) {
        this.activeProfiles.clear();
        for (String profile : profiles) {
            validateProfile(profile);
            this.activeProfiles.add(profile);
        }
    }
}

到此.我们就分析了SpringBoot启动时候环境初始化过程,本例并没有配置多环境,大家可以配置多环境,跟踪分析代码...

相关文章

  • 06--SpringBoot启动之环境初始化

    假如有开发,测试,生产三个不同的环境,需要定义三个不同环境下的配置,以properties配置为例,在Spring...

  • vagrant使用简介

    Outline 安装 初始化工作环境初始化工作目录首次启动vagrant使用vagrant中的ubuntu环境同步...

  • mysql安装

    环境 windows10 + WLS 安装 初始化及启动 出错 执行初始化命令时也发生错误: 报错: 执行启动命令...

  • uos linux启动流程

    设备加电->加载bios->读取主引导记录->启动加载器->(加载内核->初始化环境->配置系统环境->启动内核模...

  • 操作系统学习笔记(六)

    操作系统的启动 启动过程 从加电到用户工作环境准备好的过程。 (1) 初始引导(2) 核心初始化(3) 系统初始化...

  • 108MongoDB 基础教程--高级查询与索引

    高级查询与索引 初始化环境 启动 MongoDB 服务,因为 MongoDB 并不随系统一起启动,可能以下命令运行...

  • 107MongoDB 基础教程--查询、索引与聚合

    开发准备 初始化环境启动 MongoDB 服务,因为 MongoDB 并不随系统一起启动,可能以下命令运行后会等一...

  • 小程序启动时候发生了什么

    准备运行环境: 在小程序启动前,微信会先启动双线程环境,并在线程中完成小程序基础库的初始化和预执行。 小程序基础库...

  • Linux安装Mysql

    修改配置文件 修改环境变量 创建目录 初始化 启动与停止 修改初始密码

  • Android 启动过程分析

    简述流程如下: 硬件环境初始化,内核被加载到内存; 内核引导阶段, 初始化并启动用户空间1号进程(init); i...

网友评论

      本文标题:06--SpringBoot启动之环境初始化

      本文链接:https://www.haomeiwen.com/subject/dferiftx.html