Spring Boot 使你可以将配置外部化,以便在不同的环境中使用相同的应用程序代码。你可以使用 properties 文、YAML 文、环境变量和命令行参数来对配置进行外部化。属性值可以通过
Spring Boot 使用一个非常特殊的
为了提供一个具体的例子,假设你开发了一个使用 import org.springframework.stereotype.*; import org.springframework.beans.factory.annotation.*; @Component public class MyBean { @Value("${name}") private String name; // ... }
在你的应用程序类路径(例如,在 jar 中)上可以有一个为
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]}
默认情况下,
如果你不想命令行属性能添加到
列表按优先级排序(在列表中较高的位置定义的属性重写那些在较低位置定义的属性)。
如果你不喜欢 $ java -jar myproject.jar --spring.config.name=myproject 下面的示例展示如何指定两个位置: $ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
如果
配置位置以相反的顺序搜索。默认情况下,配置的位置是
当自定义配置位置使用
或者,当使用
此搜索顺序允许你在一个配置文件中指定默认值,然后在另一个配置文件中有选择的重写这些值。你可以在一个默认位置中的
除了
特定配置组属性从标准
如果指定了多个配置组,则应用最后一个胜利的策略。例如,
app.name=MyApp app.description=${app.name} is a Spring Boot application
YAML 是一个 JSON 的超集,因此,它是一种用于指定分层属性数据的方便格式。当你的类路径上有 SnakeYAML 库时,
Spring Framework 提供两个可用于加载 YAML 文档的便利类。 例如,参考下面的 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 列表表示为 my: servers: - dev.example.com - another.example.com 前面的示例将被转换成以下属性: my.servers[0]=dev.example.com my.servers[1]=another.example.com
要像 Spring Boot 的 @ConfigurationProperties(prefix="my") public class Config { private List<String> servers = new ArrayList<String>(); public List<String> getServers() { return this.servers; } }
你可以使用 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
在前面的示例中,如果
如果在应用程序上下文启动时没有显式激活,则激活默认配置组,因此,在下面的 YAML 中,我们为 server: port: 8000 --- spring: profiles: default security: user: password: weak 然而,在下面的示例中,密码总是被设置,因为它不附加到任何配置文件中,并且在必要时,必须在所有其它配置文件中显式重置: server: port: 8000 spring: security: user: password: weak
使用
使用 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 定义了以下属性:
你还需要列出属性类以注册在 @Configuration @EnableConfigurationProperties(AcmeProperties.class) public class MyConfiguration { }
即使前面的配置为 @Component @ConfigurationProperties(prefix="acme") public class AcmeProperties { // ... see the preceding example }
这种配置方式与 # application.yml acme: remote-address: 192.168.1.1 security: username: admin roles: - USER - ADMIN # additional configuration as required
若要使用 @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()); // ... } }
除了使用
若要从 @ConfigurationProperties(prefix = "another") @Bean public AnotherComponent anotherComponent() { ... }
所有有
Spring Boot 使用一些松散的规则来将
例如,考虑下面的 @ConfigurationProperties(prefix="acme.my-project.person") public class OwnerProperties { private String firstName; public String getFirstName() { return this.firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } } 在前面的示例中,可以使用以下属性名称: 表格 24.1. 松散的绑定
表格 24.2. 每个属性源的松散绑定规则
当绑定到 acme: map: "[/key1]": value1 "[/key2]": value2 /key3: value3
上面的属性使用 当列表在多个位置配置时,通过替换整个列表来重写。
例如,假设 @ConfigurationProperties("acme") public class AcmeProperties { private final List<MyPojo> list = new ArrayList<>(); public List<MyPojo> getList() { return this.list; } } 考虑以下配置: acme: list: - name: my name description: my description --- spring: profiles: dev acme: list: - name: my another name
如果 当在多个配置文件中指定一个列表时,使用具有最高优先级的列表(并且只有一个)。考虑下面的例子: acme: list: - name: my name description: my description - name: another name description: another description --- spring: profiles: dev acme: list: - name: my another name
在前面的示例中,如果
对于 @ConfigurationProperties("acme") public class AcmeProperties { private final Map<String, MyPojo> map = new HashMap<>(); public Map<String, MyPojo> getMap() { return this.map; } } 考虑下面的配置: acme: map: key1: name: my name 1 description: my description 1 --- spring: profiles: dev acme: map: key1: name: dev name 1 key2: name: dev name 2 description: dev description 2
如果
Spring Boot 在绑定到
Spring Boot 有表示持续时间的专门支持。如果暴露
参考以下的示例: @ConfigurationProperties("app.system") public class AppSystemProperties { @DurationUnit(ChronoUnit.SECONDS) private Duration sessionTimeout = Duration.ofSeconds(30); private Duration readTimeout = Duration.ofMillis(1000); public Duration getSessionTimeout() { return this.sessionTimeout; } public void setSessionTimeout(Duration sessionTimeout) { this.sessionTimeout = sessionTimeout; } public Duration getReadTimeout() { return this.readTimeout; } public void setReadTimeout(Duration readTimeout) { this.readTimeout = readTimeout; } }
为了指定会话超时为 30秒, 你也可以使用任何支持的单位。它们是:
默认的单位是毫秒,可以用上面的示例中所示的
Spring Framework 具有一个
参考下面的例子: @ConfigurationProperties("app.io") public class AppIoProperties { @DataSizeUnit(DataUnit.MEGABYTES) private DataSize bufferSize = DataSize.ofMegaBytes(2); private DataSize sizeThreshold = DataSize.ofBytes(512); public DataSize getBufferSize() { return this.bufferSize; } public void setBufferSize(DataSize bufferSize) { this.bufferSize = bufferSize; } public DataSize getSizeThreshold() { return this.sizeThreshold; } public void setSizeThreshold(DataSize sizeThreshold) { this.sizeThreshold = sizeThreshold; } }
若要指定10兆字节的缓冲区大小, 你也可以使用任何支持的单位。它们是:
默认的单位是字节,可以用上面的示例中所示的
Spring Boot 会尝试校验使用 Spring 的 @ConfigurationProperties(prefix="acme") @Validated public class AcmeProperties { @NotNull private InetAddress remoteAddress; // ... getters and setters }
虽然嵌套属性在绑定时也会被校验,但是将相关字段注解为 @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 } }
你还可以通过创建一个名为
如果你为自己的组件定义了一组配置键,建议将它们在带有
最后,虽然可以在
Spring 配置组提供了一种隔离应用程序配置的部分并使其仅在某些环境下可用的方法。任何 @Configuration @Profile("production") public class ProductionConfiguration { // ... }
你可以使用 spring.profiles.active=dev,hsqldb
还可以使用以下开关在命令行上指定它:
有时,将特定配置组的属性添加到激活的配置组中而不是替换它们是有好处的。
例如,当一个应用使用下面的属性,并用 --- my.property: fromyamlfile --- spring.profiles: prod spring.profiles.include: - proddb - prodmq
你可以通过在应用程序运行之前调用
|