目录
外部化配置
Spring Boot 允许您将配置外部化,以便您可以在不同的环境中使用相同的应用程序代码。您可以使用各种外部配置源,包括 Java 属性文件、YAML 文件、环境变量和命令行参数。
属性值可以通过使用注解直接注入到你的 bean 中@Value
,通过 Spring 的抽象Environment
访问,或者通过.@ConfigurationProperties
Spring Boot 使用一种非常特殊的PropertySource
顺序,旨在允许明智地覆盖值。属性按以下顺序考虑(较低项目的值覆盖较早的项目):
- 默认属性(由设置指定
SpringApplication.setDefaultProperties
)。 @PropertySource
@Configuration
您的类上的注释。- 配置数据(例如
application.properties
文件)。 - 仅在中
RandomValuePropertySource
具有属性的random.*
- 操作系统环境变量。
- Java 系统属性 (
System.getProperties()
)。 - JNDI 属性来自
java:comp/env
. ServletContext
初始化参数。ServletConfig
初始化参数。- 来自
SPRING_APPLICATION_JSON
(嵌入在环境变量或系统属性中的内联 JSON)的属性。 - 命令行参数。
properties
属性在你的测试。@TestPropertySource
测试上的注释。$HOME/.config/spring-boot
当 devtools 处于活动状态时
配置数据文件按以下顺序考虑:
- 打包在 jar 中的应用程序属性
application.properties
(和 YAML 变体)。 - 打包在您的 jar(
application-{profile}.properties
和 YAML 变体)。 - 打包 jar(
application.properties
和 YAML 变体)之外的应用程序属性。 - 打包的 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并将它们添加到 Spring
Environment`。如前所述,命令行属性始终优先于基于文件的属性源。
如果您不想将命令行属性添加到 中Environment
,可以使用 禁用它们SpringApplication.setAddCommandLineProperties(false)
。
外部应用程序属性
当您的应用程序启动时,Spring Boot 将自动从以下位置查找并加载文件application.properties
:application.yaml
- 从类路径
- 类路径根
- 类路径
/config
包
- 从当前目录
- 当前目录
- 当前目录中的
/config
子目录 - 子目录的
/config
直接子目录
该列表按优先级排序(较低项目的值覆盖较早的项目)。加载文件中的文档被添加PropertySources
到 SpringEnvironment
中。
如果您不喜欢application
作为配置文件名,您可以通过指定spring.config.name
环境属性来切换到另一个文件名。例如,要查找myproject.properties
和myproject.yaml
文件,您可以按如下方式运行应用程序:
$ java -jar myproject.jar --spring.config.name=myproject
您还可以使用spring.config.location
environment 属性来引用显式位置。此属性接受要检查的一个或多个位置的逗号分隔列表。
以下示例显示如何指定两个不同的文件:
$ 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.location
和spring.config.additional-location
属性一起使用。
特定配置文件
除了application
属性文件,Spring Boot 还将尝试使用命名约定加载特定于配置文件的文件application-{profile}
。例如,如果您的应用程序激活了一个名为prod
并使用 YAML 文件的配置文件,那么两者application.yml
都会application-prod.yml
被考虑。
特定于配置文件的属性从与标准相同的位置加载,application.properties
特定于配置文件的文件总是覆盖非特定文件。如果指定了多个配置文件,则应用最后获胜策略。例如,如果配置文件prod,live
由spring.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
.
映射到@ConfigurationProperties
Spring 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"
要使用@ConfigurationProperties
bean,您可以像注入任何其他 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 | 大写格式,在使用系统环境变量时推荐使用。 |