springboot2.6.2系列教程之外部化配置-4

外部化配置

Spring Boot 允许您将配置外部化,以便您可以在不同的环境中使用相同的应用程序代码。您可以使用各种外部配置源,包括 Java 属性文件、YAML 文件、环境变量和命令行参数。

属性值可以通过使用注解直接注入到你的 bean 中@Value,通过 Spring 的抽象Environment访问,或者通过.@ConfigurationProperties

Spring Boot 使用一种非常特殊的PropertySource顺序,旨在允许明智地覆盖值。属性按以下顺序考虑(较低项目的值覆盖较早的项目):

  1. 默认属性(由设置指定SpringApplication.setDefaultProperties)。
  2. @PropertySource@Configuration您的类上的注释。
  3. 配置数据(例如application.properties文件)。
  4. 仅在中RandomValuePropertySource具有属性的random.*
  5. 操作系统环境变量。
  6. Java 系统属性 ( System.getProperties())。
  7. JNDI 属性来自java:comp/env.
  8. ServletContext 初始化参数。
  9. ServletConfig 初始化参数。
  10. 来自SPRING_APPLICATION_JSON(嵌入在环境变量或系统属性中的内联 JSON)的属性。
  11. 命令行参数。
  12. properties属性在你的测试。
  13. @TestPropertySource 测试上的注释。
  14. $HOME/.config/spring-boot当 devtools 处于活动状态时

配置数据文件按以下顺序考虑:

  1. 打包在 jar 中的应用程序属性application.properties(和 YAML 变体)。
  2. 打包在您的 jar(application-{profile}.properties和 YAML 变体)。
  3. 打包 jar(application.properties和 YAML 变体)之外的应用程序属性。
  4. 打包的 jar(application-{profile}.properties和 YAML 变体)之外的特定于配置文件的应用程序属性。

举一个具体的例子,假设你开发了一个@Component使用name属性的,如下例所示:

@Component
public class MyBean {

    @Value("${name}")
    private String name;

    // ...

}

在您的应用程序类路径(例如,在您的 jar 中)上,您可以有一个application.properties文件,该文件为name. 在环境中运行时,application.properties可以在 jar 之外提供一个文件,该文件覆盖name. 对于一次性测试,您可以使用特定的命令行开关(例如,java -jar app.jar --name="Spring")启动。

访问命令行属性

默认情况下,SpringApplication将任何命令行选项参数(即以 开头的参数--,例如--server.port=9000)转换为 property并将它们添加到 SpringEnvironment`。如前所述,命令行属性始终优先于基于文件的属性源。

如果您不想将命令行属性添加到 中Environment,可以使用 禁用它们SpringApplication.setAddCommandLineProperties(false)

外部应用程序属性

当您的应用程序启动时,Spring Boot 将自动从以下位置查找并加载文件application.propertiesapplication.yaml

  1. 从类路径
    1. 类路径根
    2. 类路径/config
  2. 从当前目录
    1. 当前目录
    2. 当前目录中的/config子目录
    3. 子目录的/config直接子目录

该列表按优先级排序(较低项目的值覆盖较早的项目)。加载文件中的文档被添加PropertySources到 SpringEnvironment中。

如果您不喜欢application作为配置文件名,您可以通过指定spring.config.name环境属性来切换到另一个文件名。例如,要查找myproject.propertiesmyproject.yaml文件,您可以按如下方式运行应用程序:

$ java -jar myproject.jar --spring.config.name=myproject

您还可以使用spring.config.locationenvironment 属性来引用显式位置。此属性接受要检查的一个或多个位置的逗号分隔列表。

以下示例显示如何指定两个不同的文件:

$ java -jar myproject.jar --spring.config.location=\
    optional:classpath:/default.properties,\
    optional:classpath:/override.properties

如果spring.config.location包含目录(而不是文件),它们应该以/. 在运行时,它们将附加spring.config.name在加载之前生成的名称。中指定的文件spring.config.location直接导入。

通配符位置

如果配置文件位置包含*最后一个路径段的字符,则将其视为通配符位置。加载配置时会扩展通配符,以便同时检查直接子目录。当有多个配置属性来源时,通配符位置在 Kubernetes 等环境中特别有用。

例如,如果您有一些 Redis 配置和一些 MySQL 配置,您可能希望将这两个配置分开,同时要求它们都存在于一个application.properties文件中。这可能会导致两个单独的application.properties文件安装在不同的位置,例如/config/redis/application.properties/config/mysql/application.properties. 在这种情况下,通配符位置config/*/, 将导致两个文件都被处理。

默认情况下,Spring Boot 包含config/*/在默认搜索位置中。这意味着/config将搜索 jar 之外的目录的所有子目录。

您可以自己将通配符位置与spring.config.locationspring.config.additional-location属性一起使用。

特定配置文件

除了application属性文件,Spring Boot 还将尝试使用命名约定加载特定于配置文件的文件application-{profile}。例如,如果您的应用程序激活了一个名为prod并使用 YAML 文件的配置文件,那么两者application.yml都会application-prod.yml被考虑。

特定于配置文件的属性从与标准相同的位置加载,application.properties特定于配置文件的文件总是覆盖非特定文件。如果指定了多个配置文件,则应用最后获胜策略。例如,如果配置文件prod,livespring.profiles.active属性指定,则 中的值application-prod.properties可以被 中的值覆盖application-live.properties

如果没有显式激活配置文件,则使用application-default属性。

导入附加数据

应用程序属性可以使用该属性从其他位置导入更多配置数据spring.config.import

例如,您的类路径application.properties文件中可能包含以下内容:

spring:
  application:
    name: "myapp"
  config:
    import: "optional:file:./dev.properties"
属性占位符

application.properties和中的值在使用时会application.yml通过现有值进行过滤Environment,因此您可以参考以前定义的值(例如,来自系统属性)。标准的${name}属性占位符语法可以在值内的任何地方使用。

例如,以下文件将设置app.description为“MyApp is a Spring Boot application”:

app:
  name: "MyApp"
  description: "${app.name} is a Spring Boot application"
使用多文档文件

Spring Boot 允许您将单个物理文件拆分为多个独立添加的逻辑文档。文档从上到下按顺序处理。后面的文档可以覆盖早期文档中定义的属性。

例如,以下文件有两个逻辑文档:

spring:
  application:
    name: "MyApp"
---
spring:
  application:
    name: "MyCloudApp"
  config:
    activate:
      on-cloud-platform: "kubernetes"

属性文件分隔符不能有任何前导空格,并且必须正好有三个连字符。分隔符前后的行不能是注释。

激活属性

有时仅在满足某些条件时才激活给定的一组属性很有用。例如,您可能拥有仅在特定配置文件处于活动状态时才相关的属性。

您可以使用 有条件地激活属性文档spring.config.activate.*

例如,以下内容指定第二个文档仅在 Kubernetes 上运行时才处于活动状态,并且仅当“prod”或“staging”配置文件处于活动状态时:

myprop:
  "always-set"
---
spring:
  config:
    activate:
      on-cloud-platform: "kubernetes"
      on-profile: "prod | staging"
myotherprop: "sometimes-set"

使用 YAML

YAML是 JSON 的超集,因此是一种用于指定分层配置数据的便捷格式。

将 YAML 映射到属性

YAML 文档需要从其分层格式转换为可与 Spring 一起使用的平面结构Environment。例如,考虑以下 YAML 文档:

environments:
  dev:
    url: "https://dev.example.com"
    name: "Developer Setup"
  prod:
    url: "https://another.example.com"
    name: "My Cool App"

为了从 中访问这些属性Environment,它们将被展平如下:

environments.dev.url=https://dev.example.com
environments.dev.name=Developer Setup
environments.prod.url=https://another.example.com
environments.prod.name=My Cool App

同样,YAML 列表也需要展平。它们表示为带有[index]解引用器的属性键。例如,考虑以下 YAML:

my:
 servers:
 - "dev.example.com"
 - "another.example.com"

前面的示例将转换为以下属性:

my.servers[0]=dev.example.com
my.servers[1]=another.example.com

YAML 文件不能使用@PropertySource@TestPropertySource注释加载。因此,如果您需要以这种方式加载值,则需要使用属性文件。

配置随机值

RandomValuePropertySource对于注入随机值很有用

它可以生成整数、长整数、uuid 或字符串,如下例所示:

my:
  secret: "${random.value}"
  number: "${random.int}"
  bignumber: "${random.long}"
  uuid: "${random.uuid}"
  number-less-than-ten: "${random.int(10)}"
  number-in-range: "${random.int[1024,65536]}"

类型安全的配置属性

使用@Value("${property}")注解来注入配置属性有时会很麻烦,尤其是当您使用多个属性或者您的数据本质上是分层的时。Spring Boot 提供了一种使用属性的替代方法,可以让强类型 bean 管理和验证应用程序的配置。

JavaBean 属性绑定

可以绑定声明标准 JavaBean 属性的 bean,如下例所示:

@ConfigurationProperties("my.service")
public class MyProperties {

    private boolean enabled;

    private InetAddress remoteAddress;

    private final Security security = new Security();

    // getters / setters...

    public static class Security {

        private String username;

        private String password;

        private List<String> roles = new ArrayList<>(Collections.singleton("USER"));

        // getters / setters...

    }

}

前面的 POJO 定义了以下属性:

  • my.service.enabled,默认值为false
  • my.service.remote-address, 具有 强制转换的类型String
  • my.service.security.username,具有嵌套的“安全”对象,其名称由属性的名称确定。特别是,那里根本没有使用该类型,并且可能已经使用了SecurityProperties.
  • my.service.security.password.
  • my.service.security.roles, 集合String默认为USER.

映射到@ConfigurationPropertiesSpring Boot 中可用的类的属性,通过属性文件、YAML 文件、环境变量和其他机制配置,是公共 API,但类本身的访问器(getter/setter)并不意味着直接使用.

这种安排依赖于默认的空构造函数,并且 getter 和 setter 通常是强制性的,因为绑定是通过标准 Java Beans 属性描述符进行的,就像在 Spring MVC 中一样。

有些人使用 Project Lombok 来自动添加 getter 和 setter。确保 Lombok 不会为此类类型生成任何特定的构造函数,因为容器会自动使用它来实例化对象。

启用

Spring Boot 提供了绑定@ConfigurationProperties类型并将它们注册为 bean 的基础设施。您可以按类启用配置属性,也可以启用与组件扫描类似的配置属性扫描。

有时,带有注释的类@ConfigurationProperties可能不适合扫描,例如,如果您正在开发自己的自动配置或希望有条件地启用它们。在这些情况下,请使用@EnableConfigurationProperties注释指定要处理的类型列表。这可以在任何@Configuration类上完成,如下例所示:

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(SomeProperties.class)
public class MyConfiguration {

}

要使用配置属性扫描,请将@ConfigurationPropertiesScan注释添加到您的应用程序。通常,它被添加到带有注释的主应用程序类中,@SpringBootApplication但它可以添加到任何@Configuration类中。默认情况下,扫描将从声明注解的类的包中进行。如果要定义要扫描的特定包,可以按照以下示例进行操作:

@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "com.example.another" })
public class MyApplication {

}
使用

这种配置风格特别适用于SpringApplication外部 YAML 配置,如下例所示:

my:
  service:
    remote-address: 192.168.1.1
    security:
      username: "admin"
      roles:
      - "USER"
      - "ADMIN"

要使用@ConfigurationPropertiesbean,您可以像注入任何其他 bean 一样注入它们,如以下示例所示:

@Service
public class MyService {

    private final SomeProperties properties;

    public MyService(SomeProperties properties) {
        this.properties = properties;
    }

    public void openConnection() {
        Server server = new Server(this.properties.getRemoteAddress());
        server.start();
        // ...
    }

    // ...

}
三方配置

除了@ConfigurationProperties用于注释类之外,您还可以在公共@Bean方法上使用它。当您想要将属性绑定到您无法控制的第三方组件时,这样做会特别有用。

要从Environment属性配置 bean,请添加@ConfigurationProperties到其 bean 注册,如以下示例所示:

@Configuration(proxyBeanMethods = false)
public class ThirdPartyConfiguration {

    @Bean
    @ConfigurationProperties(prefix = "another")
    public AnotherComponent anotherComponent() {
        return new AnotherComponent();
    }

}

使用前缀定义的任何 JavaBean 属性都以类似于前面示例的方式another映射到该bean。

轻松绑定

Spring Boot 使用一些宽松的规则将Environment属性绑定到bean,因此属性名称和 bean 属性名称@ConfigurationProperties之间不需要完全匹配。Environment这很有用的常见示例包括破折号分隔的环境属性(例如,context-path绑定到contextPath)和大写环境属性(例如,PORT绑定到port)。

例如,考虑以下@ConfigurationProperties类:

@ConfigurationProperties(prefix = "my.main-project.person")
public class MyPersonProperties {

    private String firstName;

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

}

使用上述代码,可以使用以下属性名称:

财产笔记
my.main-project.person.first-name烤肉盒,推荐用于.properties.yml文件。
my.main-project.person.firstName标准驼峰式语法。
my.main-project.person.first_name下划线表示法,这是在文件中使用的另一种.properties格式.yml
MY_MAINPROJECT_PERSON_FIRSTNAME大写格式,在使用系统环境变量时推荐使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吕布辕门

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值