Spring Boot的外部化配置揭秘 - piotr

19-03-28 banq
    

Spring Boot中有一些我非常喜欢的东西,其中一个是外化配置。Spring Boot允许您以多种方式配置应用程序。您能加载17个级别配置属性。所有这些都在Spring Boot文档的第24章中的此处提供描述。

本文的灵感来自于与开发人员就其应用程序配置问题进行的最后一次会谈。他们没有听说过一些有趣的功能,这些功能可以使用起来更灵活和更清晰。

默认情况下,Spring Boot试图)从以下位置:classpath:/,classpath:/config/,file:./,file:./config/加载application.properties(或application.yml)。当然,我们可以覆盖它。您可以通过设置环境属性spring.config.name来更改主配置文件的名称,或者只需通过设置属性spring.config.location来更改整个搜索路径。它可以包含目录名称以及文件路径。

让我们考虑以下情况。我们希望定义不同级别的配置,例如,应用于所有应用程序的全局属性将被仅为单个应用程序定义的特定设置覆盖。我们有三个配置源。

global.yml
property1: global
property2: global
property3: global

override.yml
property2: override
property3: override

app.yml
property3: app

结果在下面的测试中可见。正确设置属性源的顺序非常重要,最重要的源放在最后:classpath:/global.yml,classpath:/override.yml,classpath:/app.yml。

上面的配置替换了Spring Boot使用的所有默认配置,它甚至没有尝试定位application.properties(或application.yml),而只查找spring.config.location环境变量中列出的文件。如果我们想将一些自定义配置位置添加到默认位置,我们可能会使用spring.config.additional-location变量。但是,这只有在我们想要覆盖application.yml的内部定义的设置时才有意义。我们考虑类路径上可用的以下配置文件。

application.yml
property1: app
property2: app

sample-appconfig.yml
property2: sample
property3: sample

在该测试用例中,我们使用spring.config.additional-location环境变量将sample-appconfig.yml文件包含到默认配置位置。它会覆盖property2并添加新属性property3。

如果要创建特定于配置文件的应用程序属性文件。它必须遵循命名约定:( application-{profile}.properties或application-{profile}.yml)。如果标准版application.properties或application-default.properties在默认配置位置下可用,则Spring Boot仍会加载,但优先级低于特定于配置文件的文件。

我们考虑类路径上可用的以下配置文件。

application.yml
property1: app
property2: app

application-override.yml
property2: override
property3: override

以下测试激活Spring Boot配置文件覆盖,并检查加载默认和特定于配置文件的应用程序属性的正确顺序。

应用程序还可以通过类中的@PropertySource注释包含其他属性源@Configuration。默认情况下,如果找不到此类文件,应用程序将无法启动。幸运的是,我们可以通过将属性设置ignoreResourceNotFound更改为true来实现。

@SpringBootApplication
@PropertySource(value = "classpath:/additional.yml", ignoreResourceNotFound = true)
public class ConfigApp {
 
    public static void main(String[] args) {
        SpringApplication.run(ConfigApp.class, args);
    }
 
}

通过@PropertySource注释加载的属性具有非常低的优先级(对于可用的17个级别,为16)。它们可以被默认的应用程序属性覆盖。我们还可以@TestPropertySource在JUnit测试中定义,仅为特定测试加载其他属性源。使用@PropertySource的属性文件将覆盖默认应用程序属性文件和包含的文件中定义的属性。

application.yml
property1: app
property2: app

additional.yml
property1: additional
property2: additional
property3: additional
property4: additional

additional-test.yml
property2: additional-test
property3: additional-test

以下测试说明了在源代码中使用@PropertySource和@TestPropertySource使用时的加载顺序。

上面显示的所有属性都已使用@Value注释注入到应用程序中。Spring Boot提供了另一种将配置属性注入类的方法 - 通过 @ConfigurationProperties实现。

通常@ConfigurationProperties允许您将更复杂的结构注入到应用程序中。让我们想象一下我们需要注入对象列表。每个对象都包含一些字段。这是我们的示例对象类定义。

public class Person {
 
    private String firstName;
    private String lastName;
    private int age;
 
    // getters and setters
 
}

包含Person对象列表的类应该使用注释@ConfigurationProperties。注释中的值persons-list必须与application.yml文件中定义的属性的前缀相同。

@Component
@ConfigurationProperties("persons-list")
public class PersonsList {
 
    private List<Person> persons = new ArrayList<>();
 
    public List<Person> getPersons() {
        return persons;
    }
 
    public void setPersons(List<Person> persons) {
        this.persons = persons;
    }
 
}

这是application.yml里面定义的人员名单:

persons-list.persons:
  - firstName: John
    lastName: Smith
    age: 30
  - firstName: Tom
    lastName: Walker
    age: 40
  - firstName: Kate
    lastName: Hamilton
    age: 50

以下测试注入PersonsList包含人员列表的bean,并检查它们是否与内部定义的列表匹配application.yml。

你想自己尝试一下吗?带有示例的源代码可以在存储库springboot-configuration-playground中的 GitHub上获得。