springboot properties和yml文件配置 优先级和动态切换

1.外部化配置

Spring Boot允许您外部化配置,以便您可以在不同的环境中使用相同的应用程序代码。

您可以使用属性文件,YAML文件,环境变量和命令行参数来外部化配置。

属性值可以通过@Value注解直接注射到你的bean中,通过Spring的Environment,或者通过@ConfigurationProperties

Spring Boot使用一种非常特殊的PropertySource顺序,旨在允许合理地覆盖值。按以下顺序考虑属性(优先级从高到低):

  1. Devtools 主目录上的全局设置属性(~/.spring-boot-devtools.properties当devtools处于活动状态时)。
  2. @TestPropertySource 测试代码的属性源注释。
  3. 测试代码上的properties属性
  4. 命令行参数。
  5. 来自SPRING_APPLICATION_JSON的属性。
  6. ServletConfig init参数。
  7. ServletContext init参数。
  8. 来自java:comp/env的JNDI属性。
  9. Java系统属性(System.getProperties())。
  10. OS环境变量。
  11. RandomValuePropertySource,只有在拥有random.*属性
  12. jar包外面的特定于配置文件的应用程序属性(application-{profile}.properties和YAML变体)。
  13. 打包在jar中的特定于配置文件的应用程序属性(application-{profile}.properties 以及YAML变体)。
  14. jar包之外的应用程序属性(application.properties以及YAML变体)。
  15. jar包中的应用程序属性(application.properties和YAML变体)。
  16. @PropertySource  在@Configuration类上的注释。
  17. 默认属性(由设置指定SpringApplication.setDefaultProperties)。

要提供一个具体示例,假设您开发了一个@Component使用name 属性的示例,如以下示例所示:

import org.springframework.stereotype.*;
import org.springframework.beans.factory.annotation.*;

@Component
public class MyBean {

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

    // ...

}
application.properties
name
application.properties
name
java -jar app.jar --name="Spring"

1.1配置文件加载优先级总结

默认的配置文件名为application.properties 或者 application.yml
配置属性可以通过配置文件或者其他方式提供。它们的优先级大致如下:
命令行 > 系统属性 > 环境变量 > 外部配置文件 > 内部配置文件

 

1.2配置随机值

RandomValuePropertySource对于注入随机值很有用(例如,注入秘密或测试用例)。它可以生成整数,长整数,uuids或字符串,如以下示例所示:

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

1.3访问命令行属性

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

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

1.4应用程序属性文件

SpringApplicationapplication.properties以下位置的文件加载属性并将它们添加到Spring Environment

  1. 当前目录的子目录/config
  2. 当前目录
  3. classpath 下的/config
  4. classpath根路径 /

上述列表按优先级排序(在列表中较高位置定义的属性将覆盖在较低位置中定义的属性)。

 

如果您不喜欢application.properties配置文件名,可以通过指定spring.config.name环境属性切换到另一个文件名。

您还可以使用spring.config.location环境属性(以逗号分隔的目录位置或文件路径列表)来显示指定属性文件位置。以下示例显示指定其他文件名作为属性文件:

java -jar myproject.jar --spring.config.name=myproject
以下示例显示如何指定两个位置:
$ java -jar myproject.jar --spring.config.location = classpath:/default.properties,classpath:/override.properties

如果spring.config.location包含目录(而不是文件),它们应该以/(并且在运行时,附加spring.config.name 在加载之前生成的名称,包括特定于配置文件的文件名)结束。

搜索以配置位置相反的顺序。默认情况下,配置的位置是 classpath:/,classpath:/config/,file:./,file:./config/。生成的搜索顺序如下:

  1. file:./config/
  2. file:./
  3. classpath:/config/
  4. classpath:/

使用时配置自定义配置位置时spring.config.location,它们会替换默认位置。例如,如果spring.config.location配置了值classpath:/custom-config/,file:./custom-config/,则搜索顺序将变为:

  1. file:./custom-config/
  2. classpath:custom-config/

或者,当使用配置自定义配置位置时spring.config.additional-location,除了配置路径外,还会使用默认位置。在默认位置之前搜索其他位置。例如,如果classpath:/custom-config/,file:./custom-config/配置了其他位置,则搜索顺序将变为以下内容:

  1. file:./custom-config/
  2. classpath:custom-config/
  3. file:./config/
  4. file:./
  5. classpath:/config/
  6. classpath:/

此搜索顺序允许您在一个配置文件中指定默认值,然后有选择地覆盖另一个配置文件中的值。您可以在其中一个默认位置为您的应用程序提供默认值application.properties(或您选择的任何其他名称 spring.config.name)。

然后,可以在运行时使用位于其中一个自定义位置的不同文件覆盖这些默认值。

 

 

1.5特定于配置文件的属性

application.properties文件外,还可以使用以下命名约定来定义特定于配置文件的属性:application-{profile}.properties

在 Environment具有一组默认的配置文件(默认[default])如果没有设置激活的profile(spring.profiles.active)。换句话说,如果没有显式激活配置文件,则从application-default.properties加载属性。

特定于配置文件的属性从标准的相同位置加载 application.properties,特定于配置文件的文件始终覆盖非特定文件,无论特定于配置文件的文件是在打包的jar内部还是外部。

 

1.6属性中的占位符

使用时,application.properties的值将通过现有Environment值进行过滤 ,因此您可以使用先前定义的值(例如,使用“系统”属性)。

app.name=MyApp
app.description=${app.name} is a Spring Boot application

1.7使用YAML而不是properties文件

YAML是JSON的超集。

1.7.1加载YAML

Spring Framework提供了两个方便的类,可用于加载YAML文档。YamlPropertiesFactoryBean加载YAML作为Properties,YamlMapFactoryBean 加载YAML作为Map

例如,请考虑以下YAML文档:

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

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

environments.dev.url=http://dev.example.com
environments.dev.name=Developer Setup
environments.prod.url=http://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

要通过使用Spring Boot的Binder实用程序(类似 @ConfigurationProperties)绑定到这样的属性,您需要在目标bean中具有属性类型java.util.List(或Set), 并且您需要提供setter或使用可变值初始化它。例如,以下示例绑定到前面显示的属性:

@ConfigurationProperties(prefix="my")
public class Config {

    private List<String> servers = new ArrayList<String>();

    public List<String> getServers() {
        return this.servers;
    }
}

1.7.2在Spring环境中公开YAML作为属性

YamlPropertySourceLoader类可用于暴露YAML作为PropertySource在spring Environment。这样做允许您使用@Value带占位符语法的注释来访问YAML属性。需要额外配置。

1.7.3 Multi-profile YAML文档

您可以使用spring.profiles键指定文档何时适用,在单个文件中指定多个特定于配置文件的YAML文档 ,如以下示例所示:

server:
    address: 192.168.1.100
---
spring:
    profiles: development
server:
    address: 127.0.0.1
---
spring:
    profiles: production & eu-central
server:
    address: 192.168.1.120

在前面的示例中,如果development配置文件处于活动状态,则server.address 属性为127.0.0.1

同样,如果production  eu-central配置文件处于活动状态,则server.address属性为192.168.1.120

如果development, productioneu-central在配置文件没有启用,那么该属性的值192.168.1.100

如果在应用程序上下文启动时没有显式激活,则激活默认配置文件。因此,在以下YAML中,我们设置的值在“默认”配置文件中spring.security.user.password 可用:

server:
  port: 8000
---
spring:
  profiles: default
  security:
    user:
      password: weak

然而,在以下示例中,始终设置密码,因为它未附加到任何配置文件,并且可以根据需要在所有其他配置文件中显式重置密码:

server:
  port: 8000
spring:
  security:
    user:
      password: weak

通过使用spring.profiles元素指定激活的profile。

1.7.4 YAML缺点

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

1.8类型安全配置属性

使用@Value("${property}")注释注入配置属性有时会很麻烦,尤其是在使用多个属性或数据本质上是分层的情况下。

Spring Boot提供了一种使用属性的替代方法,该方法允许强类型bean管理和验证应用程序的配置,如以下示例所示:

package com.example;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("acme")
public class AcmeProperties {

    private boolean enabled;

    private InetAddress remoteAddress;

    private final Security security = new Security();

    public boolean isEnabled() { ... }

    public void setEnabled(boolean enabled) { ... }

    public InetAddress getRemoteAddress() { ... }

    public void setRemoteAddress(InetAddress remoteAddress) { ... }

    public Security getSecurity() { ... }

    public static class Security {

        private String username;

        private String password;

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

        public String getUsername() { ... }

        public void setUsername(String username) { ... }

        public String getPassword() { ... }

        public void setPassword(String password) { ... }

        public List<String> getRoles() { ... }

        public void setRoles(List<String> roles) { ... }

    }
}

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

  • acme.enabled,默认值为false。
  • acme.remote-address
  • acme.security.username,使用嵌套的“安全”对象,其名称由属性名称决定。特别是,那里根本没有使用返回类型SecurityProperties
  • acme.security.password
  • acme.security.rolesString集合

  (getter和setter通常是必需的,因为绑定是通过标准的Java Beans属性描述符,就像在Spring MVC中一样。)

您还需要列出要在@EnableConfigurationProperties注释中注册的属性类 ,如以下示例所示:

@Configuration
@EnableConfigurationProperties(AcmeProperties.class)
public class MyConfiguration {
}

 

即使前面的配置创建了常规bean AcmeProperties,我们也建议@ConfigurationProperties只处理环境,特别是不从上下文中注入其他bean。

话虽如此,@EnableConfigurationProperties注释也会自动应用于您的项目,以便从中配置任何注释的现有 bean 。

您可以通过确保 已经是bean 来快捷方式,如以下示例所示:

@Component
@ConfigurationProperties(prefix="acme")
public class AcmeProperties {

    // ... see the preceding example

}

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

# application.yml

acme:
    remote-address: 192.168.1.1
    security:
        username: admin
        roles:
          - USER
          - ADMIN

# additional configuration as required

要使用@ConfigurationPropertiesbean,可以使用与任何其他bean相同的方式注入它们,如以下示例所示:

@Service
public class MyService {

    private final AcmeProperties properties;

    @Autowired
    public MyService(AcmeProperties properties) {
        this.properties = properties;
    }

     //...

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

}

1.9 总结

属性文件配置大致如上所述。

重点1:属性配置文件的加载优先级,如何覆盖

重点2:如何通过profile灵活切换不同的配置

重点3:如果将配置文件中的属性自动注入到bean中

1.10 使用代码设置(新增)

System.setProperty("spring.profiles.active", "local");

或者

SpringApplication application = new SpringApplication(MyApplication.class);
application.setAdditionalProfiles("dev","animal_dev"); 
application.run(args);