这里所说的配置是指properties
文件这样的配置
Spring Boot
允许通过properties
文件, YAML
文件, Environment
变量, 命令行参数等进行配置. 属性值可以通过@Value
注入到bean中并通过Spring的Environment
访问, 或通过@ConfigurationProperties
直接绑定到对象上.
Spring Boot
所提供的配置优先级从高到低如下所示:
devtools
的全局配置(~/.spring-boot-devtools.properties
文件)(当使用了devtools
时)@TestPropertySource
声明的属性文件@SpringBootTest#properties
声明的属性SPRING_APPLICATION_JSON
属性, 环境变量或系统属性中的JSONServletConfig
初始化参数ServletContext
初始化参数java:comp/env
的JNDI属性System.getProperties()
)RandomValuePropertySource
生成的random.*
属性profile
配置文件(application-{profile}.properties
和YAML
配置)profile
配置文件(application-{profile}.properties
和YAML
配置)application.properties
和YAML
配置)application.properties
和YAML
配置)@Configuration
类)上的通过@PropertySource
注解声明的属性文件SpringApplication.setDefaultProperties
声明的默认属性在classpath:application.properties
文件里有个name
变量(假设将它打成了jar包), 当在一个新的环境中运行时,
可以通过在jar包外(即新环境的的classpath
下)提供一个application.properties
文件, 重新设置name
变量的值.
甚至在测试的时候,可以通过优先级更高的命令行参数指定name
的值(java -jar app.jar --name="Spring"
)
SpringApplication
会把所有的命令行参数(以--
开头, 如--server.port=9000
)转化为属性加载到Spring的Environment
中, 命令行参数的优先级高于配置文件
如果不想让命令行参数添加到Environment
中, 可通过SpringApplication.setAddCommandLineProperties(false)
设置
上面第5条中说的SPRING_APPLICATION_JSON
属性, 可以在命令行中指定
$ SPRING_APPLICATION_JSON='{"foo":{"bar":"spam"}}' java -jar myapp.jar // 环境变量形式
这样就相当于在Spring的Environment
中添加了foo.bar=spam
.
也可以像下面这些方式提供:
$ java -Dspring.application.json='{"foo":"bar"}' -jar myapp.jar // 系统变量
$ java -jar myapp.jar --spring.application.json='{"foo":"bar"}' // 命令行参数
或以JNDI变量java:comp/env/spring.application.json
提供
其实上面介绍的这几条优先级比较高的配置, 实际并不太常用. 命令行在测试的时候用的还算比较多
application.properties
SpringApplication
默认会加载配置文件application.properties
中的配置并加到Spring Environment
中, 该文件的加载有个优先级: classpath:/config/application.properties
> classpath:/application.properties
即在classpath:/config/
下的配置文件优先级比较高. 也可以使用YAML文件(application.yml
)来替代properties文件.
application.properties
被称为Spring Boot
的外露配置, 文件中有很多属性可用来配置整个应用, 比如server.port=8080
等; 你可以通过指定这些属性值来配置应用.
配置文件的名字和位置, 也可自定义, 可通过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
指定的配置文件
RandomValuePropertySource
可以注入一些随机变量, 可产生integer, long, string, uuid
等类型的随机值, 例如
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
(不包括max).
application.properties
中定义的变量已经被Environment
过滤, 所以可以引用前面定义过的变量, 比如:
app.name=MyApp
app.description=${app.name} is a Spring Boot application
application-{profile}.properties
的优先级要高于application.properties
.profile
就用于区分是dev
环境还是beta
环境还是prod
环境. 如果没有被指定, 默认会使用application-default.properties
配置.profile
, 可以在application.properties
中通过属性spring.profiles.active=profile
来指定, 在profile
配置文件中指定该属性不起作用.举个例子, application.properties
中有个默认属性server.port=8080
用于指定服务的端口. 假设有下面的文件, 文件内容如下:
// application.properties
server.port=8080
spring.profiles.active=dev
// application-default.properties
server.port=8081
// application-dev.properties
server.port=8082
// application-prod.properties
server.port=8083
假设application.properties
中不指定spring.profiles.active
属性, 则application-default.properties
中的8081端口生效, 若指定spring.profiles.active=prod
, 则8083端口生效. 访问8080端口都会找不到服务
Spring Boot
默认加载application.properties
中的配置, 这个文件中的默认属性相当多…
如果我们要加载自己的配置, 比如下面的数据库配置:
db.driver=MySQL
db.username=username
db.password=123456
db.tables[0]=table1
db.tables[1]=table2
可以把这些属性直接放到application.properties
中, 但极力不推荐这样.
我们一般都是定义自己的配置文件, 比如把这些属性放到db.properties
文件. 然后通过@PropertySource
加载配置文件, 然后通过@Value("${key:defaultVlaue}")
的形式进行配置, 如下:
@Component
@PropertySource("db.properties")
public class DBConfig {
@Value("${db.driver}")
private String driver;
@Value("${db.username}")
private String username;
@Value("${db.password}")
private String password;
@Value("${db.tables[0]}")
private String table1;
@Value("${db.tables[1]}")
private String table2;
}
注: properties
文件默认是按照unicode加载, 若有中文, 一定要指定编码@PropertySource(value = "db.properties", encoding = "UTF-8")
上面这种方式在Spring Framework
普遍使用, 但是 Spring Boot
提供了更高级的使用配置的方式,类似于Spring
中的DataBinder
工具. 还是db.properties
文件, 我们可以这样进行数据绑定:
@Data
@Component
@ConfigurationProperties(prefix="db", locations = "classpath:db.properties")
public class DBConfig {
private String driver;
private String username;
private String password;
private List<String> tables;
}
最上面的@Data
是Lombok
包中用于生成getter, setter
等的注解, pom依赖为:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
不用这个包也可以, 那就需要自己写 getter
和setter
方法了
另外注意此时该类上是加了@Component
注解的, 这样才会被当作Spring的Bean.
其实不在DBConfig
上加@Component
注解也有办法, 通常@ConfigurationProperties
是和@EnableConfigurationProperties
一起使用的, @EnableConfigurationProperties
注解需要加到配置类上.
像下面这样使用:
// 配置类
@SpringBootApplication
@EnableConfigurationProperties({DBConfig.class})
public class Application {
// 代码
}
// 加载属性的类(主意这个类没有加 @Component 注解)
@ConfigurationProperties(prefix="db", locations = "classpath:db.properties")
public class DBConfig {
// 代码
}
这种形式, @ConfigurationProperties
bean将会以名字<prefix>-<fqn>
注册, <prefix>
就是注解中指定的前缀, <fqn>
是该类的全类名. 上面的DBConfig
将会被注册成名字为db-com.example.myproject.config.DBConfig
的bean
@ConfigurationProperties
的优缺点优点:
Environment
属性名和@ConfigurationProperties Beans
属性名不需要精确匹配, 比如驼峰person.firstName
, 虚线pserson.first-name
, 下划线person.first_name
, 大写PERSON_FIRST_NAME
都能正确区分绑定@NotNull
, @NotEmpty
等(JSR-303)注解进行校验meta-data
文件(可被IDE使用)缺点:
SpEL
表达式YAML
是JSON
的超集, 有一定的结构, SpringApplication
提供了对YAML
的支持.
使用YAML
配置文件需要确保在classpath中引入了SnakeYAML
包, spring-boot-starter
中已经包含了SnakeYAML
包, 也可以主动显式地添加pom依赖:
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.17</version>
</dependency>
application.yml
Spring Boot
会自动加载这个配置, 因此效果跟application.properties
一样。
Spring 提供了两个方便的类加载YAML
, YamlPropertiesFactoryBean
把YAML
作为Properties
加载, YamlMapFactoryBean
把YAML
作为Map
加载;
YamlPropertySourceLoader
可以把YAML
作为PropertySource
加到Spring Environment
中, 这样就可以用@Value
的方式进行注入了.
比如下面的写法是一样的
// yml文件
environments:
dev:
url: http://dev.bar.com
name: Developer Setup
prod:
url: http://foo.bar.com
name: My Cool App
my:
servers:
- dev.bar.com
- foo.bar.com
// properties文件
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
my.servers[0]=dev.bar.com
my.servers[1]=foo.bar.com
YAML
配置遗憾的是, YAML
不能像properties
文件一样使用@PropertySource
注解的方式加载.
加载自定义的YAML
文件可以通过@ConfigurationProperties
注解来加载, 如:@ConfigurationProperties(prefix="db", locations = "classpath:db.yml")