读取 Springboot 的配置

简介: 读取 Springboot 的配置方式

从配置文件中获取属性应该是SpringBoot开发中最为常用的功能之一,但就是这么常用的功能,仍然有很多开发者在这个方面踩坑。

我整理了几种获取配置属性的方式,目的不仅是要让大家学会如何使用,更重要的是弄清配置加载、读取的底层原理,一旦出现问题可以分析出其症结所在,而不是一报错取不到属性,无头苍蝇般的重启项目,在句句卧槽中逐渐抓狂~

以下示例源码 Springboot 版本均为 2.7.6

下边我们一一过下这几种玩法和原理,看看有哪些是你没用过的!话不多说,开始搞~

一、Environment

使用 Environment 方式来获取配置属性值非常简单,只要注入Environment类调用其方法getProperty(属性key)即可,但知其然知其所以然,简单了解下它的原理,因为后续的几种获取配置的方法都和它息息相关。

@Slf4j
@SpringBootTest
public class EnvironmentTest {
    @Resource
    private Environment env;
    @Test
    public void var1Test() {
        String var1 = env.getProperty("env101.var1");
        log.info("Environment 配置获取 {}", var1);
    }
}

1、什么是 Environment?

Environment 是 springboot 核心的环境配置接口,它提供了简单的方法来访问应用程序属性,包括系统属性、操作系统环境变量、命令行参数、和应用程序配置文件中定义的属性等等。

2、配置初始化

Springboot 程序启动加载流程里,会执行SpringApplication.run中的prepareEnvironment()方法进行配置的初始化,那初始化过程每一步都做了什么呢?

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
   DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
      /** 
      * 1、创建 ConfigurableEnvironment 对象:首先调用 getOrCreateEnvironment() 方法获取或创建
      * ConfigurableEnvironment 对象,该对象用于存储环境参数。如果已经存在 ConfigurableEnvironment 对象,则直接使用它;否则,根据用户的配置和默认配置创建一个新的。
      */
      ConfigurableEnvironment environment = getOrCreateEnvironment();
      /**
      * 2、解析并加载用户指定的配置文件,将其作为 PropertySource 添加到环境对象中。该方法默认会解析 application.properties 和 application.yml 文件,并将其添加到 ConfigurableEnvironment 对象中。
      * PropertySource 或 PropertySourcesPlaceholderConfigurer 加载应用程序的定制化配置。
      */
      configureEnvironment(environment, applicationArguments.getSourceArgs());
      // 3、加载所有的系统属性,并将它们添加到 ConfigurableEnvironment 对象中
      ConfigurationPropertySources.attach(environment);
      // 4、通知监听器环境参数已经准备就绪
      listeners.environmentPrepared(bootstrapContext, environment);
      /**
      *  5、将默认的属性源中的所有属性值移到环境对象的队列末尾,
      这样用户自定义的属性值就可以覆盖默认的属性值。这是为了避免用户无意中覆盖了 Spring Boot 所提供的默认属性。
      */
      DefaultPropertiesPropertySource.moveToEnd(environment);
      Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
          "Environment prefix cannot be set via properties.");
      // 6、将 Spring Boot 应用程序的属性绑定到环境对象上,以便能够正确地读取和使用这些配置属性
      bindToSpringApplication(environment);
      // 7、如果没有自定义的环境类型,则使用 EnvironmentConverter 类型将环境对象转换为标准的环境类型,并添加到 ConfigurableEnvironment 对象中。
      if (!this.isCustomEnvironment) {
        EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
        environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
      }
      // 8、再次加载系统配置,以防止被其他配置覆盖
      ConfigurationPropertySources.attach(environment);
      return environment;
}

看看它的配置加载流程步骤:

  • 创建 环境对象ConfigurableEnvironment 用于存储环境参数;
  • configureEnvironment 方法加载默认的 application.propertiesapplication.yml 配置文件;以及用户指定的配置文件,将其封装为 PropertySource 添加到环境对象中;
  • attach(): 加载所有的系统属性,并将它们添加到环境对象中;
  • listeners.environmentPrepared(): 发送环境参数配置已经准备就绪的监听通知;
  • moveToEnd(): 将 系统默认 的属性源中的所有属性值移到环境对象的队列末尾,这样用户自定义的属性值就可以覆盖默认的属性值。
  • bindToSpringApplication: 应用程序的属性绑定到 Bean 对象上;
  • attach(): 再次加载系统配置,以防止被其他配置覆盖;

上边的配置加载流程中,各种配置属性会封装成一个个抽象的数据结构 PropertySource中,这个数据结构代码格式如下,key-value形式。

public abstract class PropertySource<T> {
    protected final String name; // 属性源名称
    protected final T source; // 属性源值(一个泛型,比如Map,Property)
    public String getName();  // 获取属性源的名字  
    public T getSource(); // 获取属性源值  
    public boolean containsProperty(String name);  //是否包含某个属性  
    public abstract Object getProperty(String name);   //得到属性名对应的属性值   
}

PropertySource 有诸多的实现类用于管理应用程序的配置属性。不同的 PropertySource 实现类可以从不同的来源获取配置属性,例如文件、环境变量、命令行参数等。其中涉及到的一些实现类有:

关系图

  • MapPropertySource: Map 键值对的对象转换为 PropertySource 对象的适配器;
  • PropertiesPropertySource: Properties 对象中的所有配置属性转换为 Spring 环境中的属性值;
  • ResourcePropertySource: 从文件系统或者 classpath 中加载配置属性,封装成 PropertySource对象;
  • ServletConfigPropertySource: Servlet 配置中读取配置属性,封装成 PropertySource 对象;
  • ServletContextPropertySource: Servlet 上下文中读取配置属性,封装成 PropertySource 对象;
  • StubPropertySource: 是个空的实现类,它的作用仅仅是给 CompositePropertySource 类作为默认的父级属性源,以避免空指针异常;
  • CompositePropertySource: 是个复合型的实现类,内部维护了 PropertySource集合队列,可以将多个 PropertySource 对象合并;
  • SystemEnvironmentPropertySource: 操作系统环境变量中读取配置属性,封装成 PropertySource 对象;

上边各类配置初始化生成的 PropertySource 对象会被维护到集合队列中。

List<PropertySource<?>> sources = new ArrayList<PropertySource<?>>()

配置初始化完毕,应用程序上下文AbstractApplicationContext会加载配置,这样程序在运行时就可以随时获取配置信息了。

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
   ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
   ApplicationArguments applicationArguments, Banner printedBanner) {
    // 应用上下文加载环境对象
  context.setEnvironment(environment);
  postProcessApplicationContext(context);
    .........
  }
目录
相关文章
|
2天前
|
运维 Java Spring
Springboot配置文件读取
Springboot配置文件读取
|
2天前
|
Java
SpringBoot获取配置中的数据
SpringBoot获取配置中的数据
37 0
|
9月前
|
Java 数据格式 容器
如何读懂 SpringBoot 配置文件
如何读懂 SpringBoot 配置文件
65 0
|
6月前
|
Java 数据格式
Springboot读取yml文件参数
Springboot读取yml文件参数
|
9月前
|
Java Spring
Springboot读取配置
Springboot读取配置
55 0
|
9月前
|
Java
springboot读取yml配置文件的三种方式
springboot读取yml配置文件的三种方式
136 0
|
10月前
|
XML Java 数据格式
SpringBoot配置文件 | 多环境配置 | 读取配置的4种方式
SpringBoot配置文件 | 多环境配置 | 读取配置的4种方式
|
11月前
|
Java 开发者 Spring
SpringBoot修改配置
Spring修改配置的方式有以下几种: 1.修改配置文件 首先清楚直接能在SpringBoot配置文件中修改的属性,必须是自动配置类绑定在配置文件类中的属性。如果自动配置类根本就没有绑定配置文件类,那么SpringBoot配置文件中无法直接修改。 2.自定义组件 绑定了配置类的依赖类可以直接去通过配置文件修改,但是有些依赖类并没有绑定配置文件类,这样就不能通过SpringBoot的配置文件去直接修改配置。
271 0
|
XML Java 数据格式
Springboot读取配置的10种方式
Spring Boot 读取配置文件的方式有很多,下面介绍 10 种常用方式以及相应的示例和解析。
280 0
|
Java Maven Spring
springboot配置不同环境读取不同文件
以下是本人暂时了解的知识,写出来用于笔记同时方便大家使用。如有问题之处,欢迎朋友指正。
141 0
springboot配置不同环境读取不同文件