Spring Boot允许您将配置外部化,以便可以在不同的环境中使用相同的应用程序代码。您可以使用属性文件、YAML文件、环境变量和命令行参数来具体化配置。属性值可以通过使用@Value注释直接注入bean,可以通过Spring的环境抽象访问,也可以通过@ConfigurationProperties绑定到结构化对象。

Spring Boot使用一种非常特殊的PropertySource顺序,其设计目的是允许合理地覆盖值。属性按以下顺序考虑:

  1. Devtools global settings properties in the $HOME/.config/spring-boot folder when devtools is active.

  2. @TestPropertySource annotations on your tests.

  3. properties attribute on your tests. Available on @SpringBootTest and the test annotations for testing a particular slice of your application.

  4. Command line arguments.

  5. Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property).

  6. ServletConfig init parameters.

  7. ServletContext init parameters.

  8. JNDI attributes from java:comp/env.

  9. Java System properties (System.getProperties()).

  10. OS environment variables.

  11. RandomValuePropertySource that has properties only in random.*.

  12. Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants).

  13. Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants).

  14. Application properties outside of your packaged jar (application.properties and YAML variants).

  15. Application properties packaged inside your jar (application.properties and YAML variants).

  16. @PropertySource annotations on your @Configuration classes. Please note that such property sources are not added to the Environment until the application context is being refreshed. This is too late to configure certain properties such as logging.* and spring.main.* which are read before refresh begins.

  17. Default properties (specified by setting SpringApplication.setDefaultProperties).

翻译后常见的(优先级由高->低):

  1. 命令行参数。
  2. 通过 System.getProperties() 获取的 Java 系统参数。
  3. 操作系统环境变量。
  4. 从 java:comp/env 得到的 JNDI 属性。
  5. 通过 RandomValuePropertySource 生成的“random.*”属性。
  6. 应用 Jar 文件之外的属性文件。(通过spring.config.location参数)
  7. 应用 Jar 文件内部的属性文件。
  8. 在应用配置 Java 类(包含“@Configuration”注解的 Java 类)中通过“@PropertySource”注解声明的属性文件。
  9. 通过“SpringApplication.setDefaultProperties”声明的默认属性。

  Spring Boot 的这个配置优先级看似复杂,其实是很合理的。比如命令行参数的优先级被设置为最高。
  这样的好处是可以在测试或生产环境中快速地修改配置参数值,而不需要重新打包和部署应用。

  SpringApplication 类默认会把以“--”开头的命令行参数转化成应用中可以使用的配置参数,如 “--name=Alex” 会设置配置参数 “name” 的值为 “Alex”。如果不需要这个功能,可以通过   “SpringApplication.setAddCommandLineProperties(false)” 禁用解析命令行参数。

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

import org.springframework.stereotype.*;
import org.springframework.beans.factory.annotation.*; @Component
public class MyBean { @Value("${name}")
private String name; // ... }

在你的jar包中,可以有application.properties文件来为name提供一个合理的默认属性值。也可以在新环境中提供jar包之外的application.properties文件来重新name。或者通过命令行执行:

(例如:java -jar app.jar --name="Spring")

注:可以在带有环境变量的命令行上提供SPRING_APPLICATION_JSON属性。例如在UNIX shell:

$ SPRING_APPLICATION_JSON='{"acme":{"name":"test"}}' java -jar myapp.jar

也可以支持JSON,在系统变量中使用spring.application.json :
$ java -Dspring.application.json='{"name":"test"}' -jar myapp.jar
命令行参数也执行JSON:
$ java -jar myapp.jar --spring.application.json='{"name":"test"}'

1.配置随机值

RandomValuePropertySource通常被用来注入随机值(例如secrets或test cases),它可以产生整数、长整数、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]}

2.访问命令行属性

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

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

3.应用程序属性文件

SpringApplication在以下的位置中,从application.properties文件中加载属性,并且把它们加入的Spring的环境中:

a.当前目录的/config子目录

b.当前目录

c.包的/config类路径

d.根的类路径

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

注:可以使用YAML ('.yml')文件作为'.properties'的替代。

如果我们不喜欢“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

通过命令行执行文件:

java -jar myproject.jar -Dconfig.path=/data/my/config  -Dspring.config.location=/data/my/config/

注:spring.config.name和spring.config.location在很早的时候就被用来决定要加载哪些文件。它们必须定义为环境属性。

如果spring.config.location包含目录,需以“/”结尾

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

  1. file:./config/

  2. file:./

  3. classpath:/config/

  4. classpath:/

如果spring.config.location配置的值是:classpath:/custom-config/,file:./custom-config/,搜索顺序将变成:

  1. file:./custom-config/

  2. classpath:custom-config/

如果附加配置classpath:/custom-config/,file:./custom-config/,那么搜索顺序将变成:

  1. file:./custom-config/

  2. classpath:custom-config/

  3. file:./config/

  4. file:./

  5. classpath:/config/

  6. classpath:/

这种搜索顺序允许您在一个配置文件中指定默认值,然后有选择地在另一个配置文件中覆盖这些值。可以在应用程序中为应用程序提供默认值。在一个默认位置中的属性(或您在spring.config.name中选择的任何其他基本名称)。然后可以在运行时使用位于自定义位置中的另一个文件覆盖这些默认值。

注:如果使用环境变量而不是系统属性,大多数操作系统不允许使用周期分隔的键名,但是可以使用下划线(例如,SPRING_CONFIG_NAME而不是spring.config.name)。

注:如果您的应用程序在容器中运行,那么可以使用JNDI属性(在java:comp/env中)或servlet上下文初始化参数来代替环境变量或系统属性,或者同时使用它们。

4.Profile-specific Properties(特殊概要文件的属性)

除了application.properties文件,特定于概要文件的属性也可以通过使用以下命名约定来定义:application-{profile}.properties。环境有一组默认的配置文件(默认情况下是[default]),如果没有设置活动的配置文件,就使用这些配置文件。换句话说,如果没有显式激活配置文件,则使用应用程序默认的application-default.properties加载属性。

特定的文件属性总会重写配置,无论该配置文件是jar包内还是jar包外。

如果指定了多个配置文件,则应用“最后赢”策略。例如,由spring.profiles.active指定的配置文件通过SpringApplication API配置的属性之后添加的,因此优先。

例如:

spring.profiles.active: dev

将加载配置文件:application-dev.properties

注:如果你使用spring.config.location来配置指定文件,那么这些特殊概要文件的属性都不会被考虑。如果你仍想使用特殊概要文件的属性,spring.config.location时配置目录。

5.在配置文件中使用占位符

application.properties的属性值可以被过滤,通过之前使用的已存在的环境值,我们可以返回以前定义的值。例如:

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

6.加密属性

Spring Boot不提供任何内置的对属性值加密的支持,但是,它提供了修改Spring环境中包含的值所必需的挂钩点。EnvironmentPostProcessor接口允许您在应用程序启动之前操作环境。有关详细信息,请参见howto.html。

如果您正在寻找一种安全的方式来存储凭证和密码,Spring Cloud Vault项目提供了在HashiCorp Vault中存储外部化配置的支持。

7.使用YAML替代Properties

YAML是JSON的一个超集,因此是指定分层配置数据的一种方便的格式。当您的类路径中有SnakeYAML库时,SpringApplication类自动支持YAML作为属性的替代。

注:如果您使用“starter”,SnakeYAML是由spring-boot-starter自动提供的

7.1加载YAML

Spring框架提供了两个方便的类,可用于加载YAML文档。YamlPropertiesFactoryBean将YAML加载为属性,YamlMapFactoryBean将YAML加载为map映射。

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

如果是properties配置的话:

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使用列表来替代含下标的属性:

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;
}
} 或
@ConfigurationProperties(prefix="my")
public class Config { private List<String> servers; public List<String> getServers() {
return this.servers;
} public void setServers(List<String> servers) {
return this.servers = servers;
}
}

7.2将YAML作为Spring环境中的属性公开

YamlPropertySourceLoader类可用于在Spring环境中将YAML公开为PropertySource。这样就可以使用带有占位符语法的@Value注释来访问YAML属性。

public class Config {

    @Value("${my.servers}")
private List<String> servers; public List<String> getServers() {
return this.servers;
} public void setServers(List<String> servers) {
return this.servers = servers;
}
}

7.3Multi-profile YAML文件

可以在一个单个文件中使用key为spring.profilse的配置来指定多个profile-specific 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

在前面的示例中,如果开发配置文件处于活动状态,则为服务器。地址属性是127.0.0.1。类似地,如果生产和eu-central配置文件处于活动状态,则服务器也处于活动状态。地址属性是192.168.1.120。如果未启用开发、生产和eu-central配置文件,则该属性的值为192.168.1.100。

如果在应用程序上下文启动时没有显式激活配置文件,则默认配置文件将被激活。因此,在接下来的YAML中,我们为spring.security.user设置了一个值。仅在“默认”配置文件中可用的密码:

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

然而,在下面的例子中,密码总是被设置,因为它没有附加到任何配置文件中,而且它必须在所有其他配置文件中被显式重置:

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

7.4YAML的缺点

无法使用@PropertySource注释加载YAML文件。因此,在需要以这种方式加载值的情况下,需要使用属性文件。

 在特定于概要文件的YAML文件中使用multi YAML文档语法可能导致意外的行为。例如,在一个文件中考虑以下配置:

application-dev.yml

server:
port: 8000
---
spring:
profiles: "!test"
security:
user:
password: "secret"

如果您启动应用时,使用参数--spring.profiles.active=dev。你可能希望ecurity.user.password设置为“secret”,但情况并非如此。嵌套的文档将被过滤,因为主文件名为application-dev.yml。它已经被认为是特定于概要文件的,嵌套文档将被忽略。如果想用,可以在application.yml配置。

注:我们建议您不要将特定于配置文件的YAML文件和多个YAML文档混合使用。坚持只使用其中之一。

8.类型安全的配置属性

使用@Value(“${property}”)注释来注入配置属性有时会很麻烦,特别是在处理多个属性或您的数据本质上是分层的情况下。Spring Boot提供了另一种处理属性的方法,允许强类型bean控制和验证应用程序的配置。

@Value注释是一个核心容器特性,它不提供与类型安全配置属性相同的特性。下表总结了@ConfigurationProperties和@Value支持的特性:

Feature @ConfigurationProperties @Value

Relaxed binding

Yes

No

Meta-data support

Yes

No

SpEL evaluation

No

Yes

8.1JavaBean属性绑定

可以绑定一个声明标准JavaBean属性的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, 能够被强制转换成String类型.

  • acme.security.username, 内嵌一个“安全”对象,它的名字由属性名决定。特别是,返回类型根本没有使用,可能是SecurityProperties

  • acme.security.password.

  • acme.security.roles, String类型的集合,默认值是USER.

注:Spring引导自动配置大量使用@ConfigurationProperties来轻松配置自动配置的bean。与自动配置类类似,在Spring Boot中可用的@ConfigurationProperties类仅供内部使用。映射到类的属性(通过属性文件、YAML文件、环境变量等配置)是公共API,但是类本身的内容并不意味着可以直接使用。

这种情况依赖于默认的空构造函数,getter和setter通常是强制性的。因为绑定是通过标准的Java bean属性描述符进行的,就像在Spring MVC中一样。在以下情况,可以忽略setter:

a.map 只要被初始化,只需要getter,没有必要用setter,用setter可能被改变。

b.集合和数组  可以通过索引(通常使用YAML)或使用单个逗号分隔的值(属性)来访问集合和数组。在后一种情况下,必须使用setter。我们建议始终为此类类型添加setter。如果初始化集合,请确保它不是不可变的(如上例所示)。

c.如果初始化了嵌套的POJO属性(如前面示例中的Security字段),则不需要setter。如果希望通过使用其默认构造函数动态创建实例,则需要一个setter。

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

e.最后,仅考虑标准Java Bean属性,不支持对静态属性的绑定。

8.2构造器函数绑定

package com.example;

import java.net.InetAddress;
import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.boot.context.properties.DefaultValue; @ConstructorBinding
@ConfigurationProperties("acme")
public class AcmeProperties { private final boolean enabled; private final InetAddress remoteAddress; private final Security security; public AcmeProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
} public boolean isEnabled() { ... } public InetAddress getRemoteAddress() { ... } public Security getSecurity() { ... } public static class Security { private final String username; private final String password; private final List<String> roles; public Security(String username, String password,
@DefaultValue("USER") List<String> roles) {
this.username = username;
this.password = password;
this.roles = roles;
} public String getUsername() { ... } public String getPassword() { ... } public List<String> getRoles() { ... } }
}

在这个设置中,@ConstructorBinding注释用于指示应该使用构造函数绑定。这意味着绑定器将期望找到具有希望绑定的参数的构造函数。

@ConstructorBinding类的嵌套成员(如上面示例中的安全性)也将通过其构造函数绑定。可以使用@DefaultValue指定默认值,并应用相同的转换服务将字符串值强制转换为缺失属性的目标类型。

要使用构造函数绑定,必须使用@EnableConfigurationProperties或配置属性扫描启用该类。不能使用构造函数绑定由常规Spring机制创建的bean(例如@Component bean、通过@Bean方法创建的bean或使用@Import加载的bean)

注:如果您的类有多个构造函数,您还可以直接在应该绑定的构造函数上使用@ConstructorBinding。

@ConfigurationProperties(prefix="acme")
@Validated
public class AcmeProperties { @NotNull
private InetAddress remoteAddress; @Valid
private final Security security = new Security(); // ... getters and setters public static class Security { @NotEmpty
public String username; // ... getters and setters } }

SpringBoot官方文档学习(二)Externalized Configuration(外部化配置)的更多相关文章

  1. SpringBoot官方文档学习(一)SpringApplication

    Springboot通过main方法启动,在许多情况下,委派给静态SpringApplication.run方法: public static void main(String[] args) { S ...

  2. SpringBoot官方文档学习(二)使用Spring Boot构建系统

    强烈建议您选择一个支持依赖关系管理并且可以使用发布到“ Maven Central”仓库的构建系统.我们建议您选择Maven或Gradle.其他构建系统(例如,Ant)也可以和Spring Boot一 ...

  3. SpringBoot官方文档学习(三)配置文件、日志、国际化和JSON

    一.Profiles Spring配置文件提供了一种方法来隔离应用程序配置的各个部分,并使其仅在某些环境中可用.任何@Component.@Configuration或@ConfigurationPr ...

  4. SpringBoot官方文档学习(一)开发你的第一个Spring Boot应用

    一些准备工作: 本节介绍如何开发一个简单的“ Hello World!” Web应用程序,该应用程序重点介绍Spring Boot的一些关键功能.我们使用Maven来构建该项目,因为大多数IDE都支持 ...

  5. Spring 4 官方文档学习(十二)View技术

    关键词:view technology.template.template engine.markup.内容较多,按需查用即可. 介绍 Thymeleaf Groovy Markup Template ...

  6. Spring Framework 官方文档学习(四)之Validation、Data Binding、Type Conversion(二)

    接前一篇 Spring Framework 官方文档学习(四)之Validation.Data Binding.Type Conversion(一) 本篇主要内容:Spring Type Conver ...

  7. Spring Boot 官方文档学习(一)入门及使用

    个人说明:本文内容都是从为知笔记上复制过来的,样式难免走样,以后再修改吧.另外,本文可以看作官方文档的选择性的翻译(大部分),以及个人使用经验及问题. 其他说明:如果对Spring Boot没有概念, ...

  8. Spring boot官方文档学习(一)

    个人说明:本文内容都是从为知笔记上复制过来的,样式难免走样,以后再修改吧.另外,本文可以看作官方文档的选择性的翻译(大部分),以及个人使用经验及问题. 其他说明:如果对Spring Boot没有概念, ...

  9. Spring Framework 官方文档学习(四)之Validation、Data Binding、Type Conversion

    本篇太乱,请移步: Spring Framework 官方文档学习(四)之Validation.Data Binding.Type Conversion(一) 写了删删了写,反复几次,对自己的描述很不 ...

随机推荐

  1. [转帖]Introduction to Linux monitoring and alerting

    Introduction to Linux monitoring and alerting https://www.redhat.com/sysadmin/linux-monitoring-and-a ...

  2. Vue框架 03

    Vue项目开发: 前后端完全分离 后端:提供接口数据 前端:页面转跳.页面布局.页面数据渲染全部由前端做 中间交互:请求 搭建Vue项目环境: Vue项目需要自建服务器:node node介绍: 1. ...

  3. 【宁夏区域赛】G.Pot!

    题意: 给定两个操作: MULTIPLY L R x  区间里都乘以一个数x MAX L R : 计算区间内一个2,3,5,7个数最大值. #include<bits/stdc++.h> ...

  4. ByteArray、16进制、字符串之间的转换

    ByteArray.16进制.字符串之间的转换: package fengzi.convert { import flash.utils.ByteArray; public class ByteArr ...

  5. jwt 0.9.0(一)推荐jwt理由

    本人一直有良好的写技术博文的习惯,最近研究 jwt 有点点心得,赶紧记下来. 我推荐使用jwt(Json Web Token)这种客户端存储状态方式,代替传统的服务端存储状态方式(比如redis存储s ...

  6. Oracle scott解锁 以及连接数据库

    最近公司需要使用oracle数据库,本地安装oracle进行测试,需要连接到数据库,但是发现scott账号 is locked; 原因:默认Oracle10g的scott不能登陆. 解决:(1)con ...

  7. 转 Json数据格式化

    /// <summary> /// JSON字符串格式化 /// </summary> /// <param name="json"></ ...

  8. Thomas Brinkhoff 基于路网的移动对象生成器的使用[第二版]

    Thomas Brinkhoff 基于路网的移动对象生成器的使用 Thomas Brinkhoff 基于路网的移动对象生成器的使用 相关操作的说明 相关文件的说明 运行 导入eclipse后运行时选择 ...

  9. java第三次面试总结

    这次面试是二面,由于自己的经验不足,面试的结果不是很令人满意,所以与这家公司失之交臂,在这里记录一下经历,吸取教训. 之前的一面是笔试+面试,面试是主管,今天的面试是总监.在前台招待我的时候,还跟我说 ...

  10. 定时任务 Quarzt

    Quartz.Net是一个从java版的Quartz移植过来的定时任务框架,可以实现异常灵活的定时任务. Quartz 有三个概念分别是 计划者(ISchedeler).工作(IJob).触发器(Tr ...