文章作者:Tyan
博客:noahsnail.com|CSDN|简书
24. 外部配置 Spring Boot允许你进行外部化配置,因此可以将同样的应用代码在不同的环境中运行。你可以使用属性文件,YAML文件,环境变量和命令行参数来进行外部化配置。属性值可以使用@Value
注解直接注入到你的beans中,通过Spring的Environment
抽象或通过@ConfigurationProperties
绑定到结构化对象上来访问。
Spring Boot使用非常特别的PropertySource
顺序,这个顺序的设计是为了允许值的合理重写。属性被认为是按照以下顺序:
- 根目录下的开发工具全局设置属性(当开发工具激活时为
~/.spring-boot-devtools.properties
)。 - 测试中的
@TestPropertySource
注解。 - 测试中的
@SpringBootTest#properties
注解特性。 - 命令行参数。
SPRING_APPLICATION_JSON
中的属性(环境变量或系统属性中的内联JSON嵌入)。ServletConfig
初始化参数。ServletContext
初始化参数。java:comp/env
的JNDI特性。- Java系统属性 (
System.getProperties()
)。 - 操作系统环境变量。
RandomValuePropertySource
只在random.*
中有属性。- jar包之外的指定配置文件的应用属性(
application-{profile}.properties
和YAML变量)。 - jar包之内的指定配置文件的应用属性(
application-{profile}.properties
和YAML变量)。 - jar包之外的应用属性 (
application.properties
和YAML变量)。 - jar包之内的应用属性 (
application.properties
和YAML变量)。 @Configuration
类中的@PropertySource
注解 。- 默认属性(通过
SpringApplication.setDefaultProperties
指定).
@Component
:import org.springframework.stereotype.*
import org.springframework.beans.factory.annotation.*@Component
public class MyBean {@Value("${name}")
private String name;
// ...}
在你的应用路径中(例如在你的jar内部),你可以使用
application.properties
为name
提供一个合理的默认属性值。当在新环境运行时,application.properties
可以在jar外部提供来重写name
;对于一次性测试,你可以通过指定的命令行切换来启动(例如java -jar app.jar --name="Spring"
)。SPRING_APPLICATION_JSON
可以在命令行中通过环境变量提供。例如在UNIX shell中:
$ SPRING_APPLICATION_JSON='{"foo":{"bar":"spam"}}' java -jar myapp.jar
在这个例子中,Spring的Environment
中会有foo.bar=spam
。你也可以在系统变量中提供JSON作为spring.application.json
。
$ java -Dspring.application.json='{"foo":"bar"}' -jar myapp.jar
或命令行参数:
$ java -jar myapp.jar --spring.application.json='{"foo":"bar"}'
或JNDI变量24.1 配置随机值java:comp/env/spring.application.json
当注入随机值时,
RandomValuePropertySource
是很有用的(例如,注入秘密或测试用例)。它可以产生integers
,longs
,uuids
或strings
,例如: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]}
random.int*
语法OPEN value (,max) CLOSE
,OPEN,CLOSE
可以是任何字符,value,max
是整数。如果提供了max
,则value
是最小值,max
是最大值(不包含)。24.2 访问命令行属性
默认情况下,
SpringApplication
会将任何命令行参数(以--
开头,例如--server.port=9000
)转换成property
并将其添加到Spring的Environment
中。正如前面提到的那样,命令行属性总是优先于其它的配置源。如果你想命令行属性添加到
Environment
中,你可以使用SpringApplication.setAddCommandLineProperties(false)
禁用它。24.3 应用属性文件
SpringApplication
会从以下位置的application.properties
文件中加载属性并将它们添加到Spring的Environment
中:- 当前目录的子目录
/config
- 当前目录
- classpath中的
/config
包
- classpath的根目录
你也可以使用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
如果spring.config.name
和spring.config.location
可以在早期用来决定加载哪一个文件,因此必须被定义为环境属性(通常是操作系统环境,系统属性或命令行参数)。
spring.config.location
包含目录(相对于文件而言),它们应该以/
结尾(在加载之前,在后面添加上从spring.config.name
中产生的名字,包括指定配置文件的名字)。在spring.config.location
中指定的文件按原样使用,不支持指定配置文件变量,将会被任何指定配置文件的属性覆盖。默认搜索路径一直用
classpath:,classpath:/config,file:,file:config/
,不管spring.config.location
中的值。搜索路径按从低到高排序(file:config/
最高)。如果你指定了自己的位置,它们优先于所有的默认位置并使用同样的从低到高的顺序。这样你可以在application.properties
中为你的应用设置默认值(或你可以选择spring.config.name
的其它生成文件基本名),在运行时用其它的文件覆盖它,同时保留默认值。如果你使用环境变量而不是系统属性,大多数操作系统不允许句号分隔的关键字,但你可以用下划线代替(例如,24.4 特定的profile属性SPRING_CONFIG_NAME
代替spring.config.name
)。
如果你在容器中运行,那么JNDI属性(在java:comp/env
中)或servlet上下文初始化参数也可以用来代替环境变量或系统属性。
除了
application.properties
文件之外,特定的profile属性也可以使用命名规范application-{profile}.properties
来定义。Environment
有一系列默认配置文件(默认为[default]
),如果没有设置激活的配置文件,会使用默认的配置文件(例如,如果没有激活显式的配置文件,则会加载application-default.properties
中的属性)。特定的profile属性会从相同位置加载
application.properties
,特定的profile文件总是覆盖非特定的配置文件,无论特定profile文件在你打包的jar内部还是外部。如果指定了几个配置文件,将会应用最后一个。例如,
spring.profiles.active
属性指定的配置文件在那些配置的文件之后通过SpringApplication
API添加,因此优先级更高。如果你在24.5 属性中的占位符spring.config.location
中指定了任何文件,那些文件的特定profile版本将不会被考虑。如果你也想使用特定的profile属性,在spring.config.location
中使用目录。
当使用
application.properties
中的值时,会通过现有的Environment
进行过滤,因此你可以参考前面定义的值(例如从系统属性中)。app.name=MyApp
app.description=${app.name} is a Spring Boot application
你也可以使用这个技术来创建现有的Spring Boot属性的24.6 使用YAML代替Propertiesshort
版本。怎样使用的更多细节请看70.4小节,“Use ‘short’ command line arguments”。
YAML是JSON的超集,它可以用一种非常方便的形式来指定分层配置数据。当你的类路径有SnakeYAML库时,
SpringApplication
类自动支持YAML作为properties的一个替代品。如果你使用‘Starters’,SnakeYAML将由24.6.1 加载YAML Spring框架提供了两个类用来方便的加载YAML文档。spring-boot-starter
自动提供。
YamlPropertiesFactoryBean
将加载YAML作为Properties
,YamlMapFactoryBean
将加载YAML作为Map
。例如,下面的YAML文档:
environments:
dev:
url: http://dev.bar.com
name: Developer Setup
prod:
url: http://foo.bar.com
name: My Cool App
将被转换成这些属性:
environments.dev.url=http://dev.bar.com
environments.dev.name=Developer Setup
environments.prod.url=http://foo.bar.com
environments.prod.name=My Cool App
【Spring|Spring Boot 2.0.0参考手册_中文版_Part IV_24】YAML列表通过
[index]
解引用表示为属性的key,例如这个YAML:my:
servers:
- dev.bar.com
- foo.bar.com
将被转换成这些属性:
my.servers[0]=dev.bar.com
my.servers[1]=foo.bar.com
为了像使用Spring的
DataBinder
一样(@ConfigurationProperties
的功能)绑定这些属性,你需要在类型为java.util.List
(或Set
)的目标bean中有属性,你需要提供一个setter
或用一个可变的值来对它初始化,例如,绑定上面的属性值:@ConfigurationProperties(prefix="my")
public class Config {private List servers = new ArrayList();
public List getServers() {
return this.servers;
}
}
24.6.2 在Spring Environment中公开YAML为属性
YamlPropertySourceLoader
类可以在Spring的Environment
中将YAML作为PropertySource
。这允许你使用熟悉的@Value
注解和占位符语法来访问YAML属性。24.6.3 多profile的YAML文档
你可以在单个文件中指定多个特定profile的YAML文档,当应用文档时,通过
spring.profiles
关键字来表明使用哪个文档。例如:server:
address: 192.168.1.100
---
spring:
profiles: development
server:
address: 127.0.0.1
---
spring:
profiles: production
server:
address: 192.168.1.120
在上面的例子中,如果
development
profile被激活,server.address
的值为127.0.0.1
。如果development
和production
profile不可用,server.address
的值为192.168.1.100
。当应用上下文启动时,如果没有显式的激活profile,则激活默认的profile。因此在这个YAML文件中我们仅在”default” profile中设置了
security.user.password
。server:
port: 8000
---
spring:
profiles: default
security:
user:
password: weak
在这个例子中,密码总是设置的,因为它没有添加到如何profile中,必要时我们必须在其它的profile中显式的对它重新设置:
server:
port: 8000
security:
user:
password: weak
Spring profiles被设计为使用”spring.profiles”元素可以选择性的用
!
字符进行否定。如果否定的和非否定的profile指向一个单独的文档,必须至少匹配一个非否定的profile,可能没有否定的profile进行匹配。24.6.4 YAML缺点 YAML文件不能通过
@PropertySource
注解进行加载。因此在这种情况下如果你需要加载值,你需要使用属性文件。24.6.5 合并YAML列表 正如我们上面看到的,任何YAML内容最终都要转换成属性。当通过profile重写“list“属性时,这个过程可能有违直觉。
例如,假设
MyPojo
对象的name
和description
属性默认情况下为空。从FooProperties
使用一个MyPojo
列表:@ConfigurationProperties("foo")
public class FooProperties {private final List list = new ArrayList<>();
public List getList() {
return this.list;
}}
考虑下面的配置:
foo:
list:
- name: my name
description: my description
---
spring:
profiles: dev
foo:
list:
- name: my another name
如果
dev
profile没有激活,FooProperties.list
将包含一个上面定义的MyPojo
输入。然而如果dev
profile可用,lists
仍只包含一个输入(name为“my another name”,description为空)。这个配置将不能添加第二个MyPojo
到list
中,并且它将不能合并这些项。当在多个profiles中指定一个集合时,将会使用最高优先级的那个集合(唯一的哪个):
foo:
list:
- name: my name
description: my description
- name: another name
description: another description
---
spring:
profiles: dev
foo:
list:
- name: my another name
在上面的例子中,假设
dev
profile被激活,FooProperties.list
将包含一个MyPojo
输入(name为“my another name”,description为空)。24.7 类型安全的配置属性
Boot提供了一种处理属性的可替代方法,允许强类型的beans管理和验证你的应用的配置。例如:
@ConfigurationProperties(prefix="connection")
public class ConnectionProperties {private String username;
private InetAddress remoteAddress;
// ... getters and setters}
建议添加getters和setters,绑定是通过标准的Java Beans属性描述符,像在Spring MVC中一样。对于不可变类型或那些从String
中可直接强制转换的类型,它们是强制性的。只要它们被初始化,maps,集合或数组需要getter方法,但不需要setter方法因为通过绑定起它们可以直接变化。如果有setter,可以创建Maps,集合和数组。Maps和集合可以通过getter扩展,数组扩展需要setter。如果它们有默认的构造函数,或构造函数接收可以从String
类型强制转换的值,嵌入的POJO属性也可以创建(因此setter不是强制性的)。一些人使用Lombok项目来自动添加getter和setter。
请看你也需要在@Value
和@ConfigurationProperties
之间的不同。
@EnableConfigurationProperties
注解中列出要注册的属性类:@Configuration
@EnableConfigurationProperties(ConnectionProperties.class)
public class MyConfiguration {
}
当即使上面的配置会为@ConfigurationProperties
以那种方式注册时,这个bean将有一个常规的名字:,
-是在
@ConfigurationProperties
注解中指定的环境关键字的前缀,是bean的完整合格的名字。如果注解没有提供任何前缀,则只用bean的完整合格的名字。
在上面的例子中bean名字是connection-com.example.ConnectionProperties
,假设ConnectionProperties
在com.example
包中。
ConnectionProperties
创建一个正规的bean,我们建议@ConfigurationProperties
只处理环境,特别是不从上下文中注入其它的beans。已经说过,为了任何带有@ConfigurationProperties
注解的bean可以根据Environment
属性进行配置,@EnableConfigurationProperties
注解也自动应用到你的工程中。确保ConnectionProperties
已经是一个bean,你可以简写上面的MyConfiguration
:@Component
@ConfigurationProperties(prefix="connection")
public class ConnectionProperties {// ... getters and setters}
这种风格的配置在
SpringApplication
的外部化YAML配置中工作的尤其好:# application.ymlconnection:
username: admin
remoteAddress: 192.168.1.1# additional configuration as required
为了同
@ConfigurationProperties
beans一起工作,你可以像任何其它bean一样以相同的方式注入它们:@Service
public class MyService {private final ConnectionProperties connection;
@Autowired
public MyService(ConnectionProperties connection) {
this.connection = connection;
}//...@PostConstruct
public void openConnection() {
Server server = new Server();
this.connection.configure(server);
}}
使用24.7.1 第三方配置 也可以使用@ConfigurationProperties
也允许你生成IDEs可以使用的元数据文件。更多细节请看附录B,配置元数据附录。
@ConfigurationProperties
来注解一个类,你也可以在公有的@Bean
方法上使用它。当你想绑定属性到你控制之外的第三方组件上时尤其有用。@ConfigurationProperties(prefix = "foo")
@Bean
public FooComponent fooComponent() {
...
}
任何定义的带有
foo
前缀的属性都将以类似于上面的ConnectionProperties
例子中的方式映射到FooComponent
bean中。24.7.2 松散绑定 Spring Boot使用一些松散的规则将
Environment
属性绑定到@ConfigurationProperties
beans上,因此不需要在Environment
属性名和bean属性名之间进行确切的匹配。常见的有用例子包括破折号分隔(例如,context-path绑定到contextPath),大小写(例如PORT
绑定到port
,)环境属性。例如,给定下面的
@ConfigurationProperties
类:@ConfigurationProperties(prefix="person")
public class OwnerProperties {private String firstName;
public String getFirstName() {
return this.firstName;
}public void setFirstName(String firstName) {
this.firstName = firstName;
}}
下面的属性名都可以使用:
表24.1. 松散绑定
Property | Note |
---|---|
person.firstName | 标准的驼峰写法 |
person.first-name | 破折号注解,建议在.properties 和.yml 文件中使用 |
person.first_name | 下划线注解,.properties 和.yml 文件中的可替代写法 |
PERSON_FIRST_NAME | 大写形式。当使用系统变量时推荐 |
@ConfigurationProperties
beans时,它将试图将外部的应用属性强制转换成正确的类型。如果你需要定制类型转换你可以提供一个ConversionService
bean(bean id为conversionService
),或定制属性编辑器(通过CustomEditorConfigurer
bean),或定制Converters
(带有@ConfigurationPropertiesBinding
注解的bean定义)。bean要求在应用生命周期中的早期,要确保限制24.7.4 @ConfigurationProperties验证 Spring Boot会试图验证外部化配置,默认使用JSR-303(如果它在classpath中)。你可以简单的添加JSR-303ConversionService
使用的依赖。通常,任何你要求的依赖可能在创建时不是完整初始化的。如果你定制的ConversionService
不要求配置关键字强制转换,你可能想重新命名你定制的ConversionService
,并且只依赖满足@ConfigurationPropertiesBindings
的定制转换器。
javax.validation
约束注解到你的@ConfigurationProperties
类中:@ConfigurationProperties(prefix="connection")
public class ConnectionProperties {@NotNull
private InetAddress remoteAddress;
// ... getters and setters}
为了验证嵌入的属性值,你必须注解相关的字段作为
@Valid
来触发它的校验。例如,在上面的ConnectionProperties
例子上构建:@ConfigurationProperties(prefix="connection")
public class ConnectionProperties {@NotNull
@Valid
private RemoteAddress remoteAddress;
// ... getters and setterspublic static class RemoteAddress {@NotEmpty
public String hostname;
// ... getters and setters}}
通过创建一个称为
configurationPropertiesValidator
的bean定义,你也可以添加定制的Spring Validator
。@Bean
方法应该声明静态的。配置属性验证器在应用生命周期的早期创建,声明@Bean
方法为静态方法,允许不必实例化@Configuration
类就创建bean。这避免了任何早期实例化可能引起的问题。这儿有一个属性验证的例子因此你可以看一下怎样设置它24.7.5 @ConfigurationProperties和@Valuespring-boot-actuator
模块包含一个端点,这个端点将公开所有的@ConfigurationProperties
beans。简单的将你的web浏览器指向/configprops
或用等价的JMX端点。更多细节请看产品级功能
@Value
是一种核心的容器功能,它不能作为类型安全配置属性提供同样的功能。下面的表中总结了@ConfigurationProperties
和@Value
支持的功能:功能 | @ConfigurationProperties |
@Value |
---|---|---|
松散绑定 | Yes | No |
元数据支持 | Yes | No |
SpEL评估 | No | Yes |
@ConfigurationProperties
注解的POJO中。也请注意@Value
不支持松散绑定,如果你需要用环境变量提供值,它不是一个好的选择。最后,虽然你可以在
@Value
中写表达式,但这种表达式不能从应用属性文件中处理。推荐阅读
- =======j2ee|spring用注解实现注入的@resource,@autowired,@inject区别
- jar|springboot项目打成jar包和war包,并部署(快速打包部署)
- 数据库|效率最高的Excel数据导入---(c#调用SSIS Package将数据库数据导入到Excel文件中【附源代码下载】)...
- java人生|35K 入职华为Java开发那天,我哭了(这 5 个月做的一切都值了)
- Java毕业设计项目实战篇|Java项目:在线嘿嘿网盘系统设计和实现(java+Springboot+ssm+mysql+maven)
- 微服务|微服务系列:服务发现与注册-----Eureka(面试突击!你想了解的Eureka都在这里.持续更新中......)
- java|ApplicationListener和SpringApplicationRunListener的联系
- Spring|SpringSecurity--自定义登录页面、注销登录配置
- 性能|性能工具之 Jmeter 通过 SpringBoot 工程启动
- 代码狂魔|Spring源码分析之IOC容器初始化流程