Properties and Configuration
属性与配置
本节包含有关设置和读取属性与配置设置,以及它们与 Spring Boot 应用程序交互的主题。
在构建时自动展开属性
与其硬编码一些也在项目构建配置中指定的属性,不如通过使用现有的构建配置来自动展开这些属性。这在 Maven 和 Gradle 中均可实现。
使用 Maven 自动展开属性
你可以通过使用资源过滤(resource filtering)在 Maven 项目中自动展开属性。如果你使用了 spring-boot-starter-parent,就可以通过 @..@ 占位符引用你的 Maven “project properties”,如下例所示:
- Properties
- YAML
app.encoding=@project.build.sourceEncoding@
app.java.version=@java.version@
app:
encoding: "@project.build.sourceEncoding@"
java:
version: "@java.version@"
只有生产配置会以这种方式进行过滤(换句话说,不会对 src/test/resources 应用过滤)。
如果你启用了 addResources 标志,spring-boot:run 目标会将 src/main/resources 直接添加到 classpath 中(用于热重载)。这样做会绕过资源过滤以及此功能。作为替代方案,你可以使用 exec:java 目标,或者自定义插件的配置。更多详情请参见 插件使用页面。
如果你不使用 starter parent,你需要在 pom.xml 文件的 <build/> 元素内包含以下内容:
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
你还需要在 <plugins/> 内部包含以下元素:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<configuration>
<delimiters>
<delimiter>@</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin>
如果你在配置中使用了标准的 Spring 占位符(例如 ${placeholder}),那么 useDefaultDelimiters 属性就非常重要。如果该属性未设置为 false,这些占位符可能会在构建过程中被展开。
使用 Gradle 进行自动属性扩展
你可以通过配置 Java 插件的 processResources 任务来自动展开 Gradle 项目中的属性,如下例所示:
tasks.named('processResources') {
expand(project.properties)
}
然后,你可以使用占位符来引用 Gradle 项目的属性,如下例所示:
- Properties
- YAML
app.name=${name}
app.description=${description}
app:
name: "${name}"
description: "${description}"
Gradle 的 expand 方法使用 Groovy 的 SimpleTemplateEngine,它会转换 ${..} 标记。这种 ${..} 样式与 Spring 自身的属性占位符机制冲突。若要将 Spring 属性占位符与自动展开一起使用,请按如下方式转义 Spring 属性占位符:\${..}。
外部化 SpringApplication 的配置
一个 SpringApplication 提供了 Bean 属性的 setter 方法,因此你可以在创建应用程序时使用其 Java API 来修改其行为。或者,你也可以通过在 spring.main.* 中设置属性来外部化配置。例如,在 application.properties 中,你可能会有如下设置:
- Properties
- YAML
spring.main.web-application-type=none
spring.main.banner-mode=off
spring:
main:
web-application-type: "none"
banner-mode: "off"
然后 Spring Boot 的启动横幅不会在启动时打印,并且应用程序也不会启动内嵌的 Web 服务器。
在外部配置中定义的属性会覆盖并替换通过 Java API 指定的值,但有一个显著的例外:主源(primary sources)。主源是指提供给 SpringApplication 构造函数的那些源:
- Java
- Kotlin
import org.springframework.boot.Banner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication application = new SpringApplication(MyApplication.class);
application.setBannerMode(Banner.Mode.OFF);
application.run(args);
}
}
import org.springframework.boot.Banner
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
@SpringBootApplication
object MyApplication {
@JvmStatic
fun main(args: Array<String>) {
val application = SpringApplication(MyApplication::class.java)
application.setBannerMode(Banner.Mode.OFF)
application.run(*args)
}
}
或者传递给 SpringApplicationBuilder 的 sources(…) 方法:
- Java
- Kotlin
import org.springframework.boot.Banner;
import org.springframework.boot.builder.SpringApplicationBuilder;
public class MyApplication {
public static void main(String[] args) {
new SpringApplicationBuilder()
.bannerMode(Banner.Mode.OFF)
.sources(MyApplication.class)
.run(args);
}
}
import org.springframework.boot.Banner
import org.springframework.boot.builder.SpringApplicationBuilder
object MyApplication {
@JvmStatic
fun main(args: Array<String>) {
SpringApplicationBuilder()
.bannerMode(Banner.Mode.OFF)
.sources(MyApplication::class.java)
.run(*args)
}
}
根据上面的示例,如果我们有以下配置:
- Properties
- YAML
spring.main.sources=com.example.MyDatabaseConfig,com.example.MyJmsConfig
spring.main.banner-mode=console
spring:
main:
sources: "com.example.MyDatabaseConfig,com.example.MyJmsConfig"
banner-mode: "console"
实际应用程序将显示 banner(由配置覆盖)并使用三个来源来构建 ApplicationContext。应用程序的来源包括:
-
MyApplication(来自代码) -
MyDatabaseConfig(来自外部配置) -
MyJmsConfig(来自外部配置)
更改应用程序外部属性的位置
默认情况下,来自不同来源的属性会按照定义的顺序添加到 Spring Environment 中(具体顺序请参见“Spring Boot 特性”一节中的 Externalized Configuration)。
你也可以提供以下系统属性(或环境变量)来更改行为:
-
spring.config.name(SPRING_CONFIG_NAME):默认值为application,作为文件名的根。 -
spring.config.location(SPRING_CONFIG_LOCATION):要加载的文件(例如 classpath 资源或 URL)。会为此文档设置一个独立的 Environment 属性源,并且可以通过系统属性、环境变量或命令行进行覆盖。
无论你在环境中设置什么,Spring Boot 始终会按照上述方式加载 application.properties。默认情况下,如果使用 YAML,则扩展名为 ‘.yaml’ 和 ‘.yml’ 的文件也会被添加到列表中。
如果你想要获取有关正在加载的文件的详细信息,可以将 org.springframework.boot.context.config 的日志级别设置为 trace。
使用“短”命令行参数
有些人喜欢在命令行上使用(例如)--port=9000 而不是 --server.port=9000 来设置配置属性。你可以通过在 application.properties 中使用占位符来启用此行为,如下例所示:
- Properties
- YAML
server.port=${port:8080}
server:
port: "${port:8080}"
如果你继承了 spring-boot-starter-parent POM,maven-resources-plugin 的默认过滤器标记已从 ${*} 更改为 @(即使用 @maven.token@ 而不是 ${maven.token}),以避免与 Spring 风格的占位符发生冲突。如果你直接为 application.properties 启用了 Maven 过滤,你可能也想将默认的过滤器标记更改为使用 其他分隔符。
在此特定情况下,端口绑定适用于 Heroku 或 Cloud Foundry 等 PaaS 环境。在这两个平台上,PORT 环境变量会自动设置,而 Spring 可以绑定到 Environment 属性的大写同义词。
使用 YAML 作为外部属性
YAML 是 JSON 的超集,因此它是一种方便的语法,可用于以分层格式存储外部属性,如下例所示:
spring:
application:
name: "cruncher"
datasource:
driver-class-name: "com.mysql.jdbc.Driver"
url: "jdbc:mysql://localhost/test"
server:
port: 9000
创建一个名为 application.yaml 的文件,并将其放在类路径(classpath)的根目录下。然后将 snakeyaml 添加到你的依赖中(Maven 坐标为 org.yaml:snakeyaml,如果你使用了 spring-boot-starter,则已自动包含)。YAML 文件会被解析为一个 Java Map<String,Object>(类似于 JSON 对象),而 Spring Boot 会将该 Map 扁平化,使其变为一层深度,并使用英文句点分隔的键,这与许多人在 Java 中使用 Properties 文件时的习惯一致。
前面的示例 YAML 对应于以下 application.properties 文件:
spring.application.name=cruncher
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost/test
server.port=9000
有关 YAML 的更多信息,请参见“Spring Boot 功能”部分中的 使用 YAML。
设置 Active Spring Profiles
Spring 的 Environment 提供了相应的 API,但通常你会设置一个系统属性(spring.profiles.active)或操作系统环境变量(SPRING_PROFILES_ACTIVE)。此外,你也可以使用 -D 参数来启动应用程序(记得将其放在主类或 jar 归档文件之前),如下所示:
$ java -jar -Dspring.profiles.active=production demo-0.0.1-SNAPSHOT.jar
在 Spring Boot 中,你也可以在 application.properties 中设置激活的 profile,如下例所示:
- Properties
- YAML
spring.profiles.active=production
spring:
profiles:
active: "production"
通过这种方式设置的值会被 System property 或环境变量的设置所替换,但不会被 SpringApplicationBuilder.profiles() 方法替换。因此,后者(Java API)可用于扩充 profiles,而不会更改默认值。
有关更多信息,请参阅“Spring Boot 功能”部分中的 Profiles。
设置默认 Profile 名称
默认配置文件(default profile)是指在没有激活任何配置文件时启用的配置文件。默认情况下,默认配置文件的名称为 default,但可以通过系统属性(spring.profiles.default)或操作系统环境变量(SPRING_PROFILES_DEFAULT)进行更改。
在 Spring Boot 中,你也可以在 application.properties 中设置默认的 profile 名称,如下例所示:
- Properties
- YAML
spring.profiles.default=dev
spring:
profiles:
default: "dev"
有关更多信息,请参见 “Spring Boot 功能” 部分中的 Profiles。
根据环境更改配置
Spring Boot 支持多文档的 YAML 和 Properties 文件(详见 使用多文档文件),这些文件可以根据激活的 profile 有条件地启用。
如果一个文档包含 spring.config.activate.on-profile 键,则其 profiles 值(一个以逗号分隔的 profile 列表或一个 profile 表达式)会被传入 Spring 的 Environment.acceptsProfiles() 方法。如果该 profile 表达式匹配,则该文档将被包含在最终的合并结果中(否则不会被包含),如下例所示:
- Properties
- YAML
server.port=9000
#---
spring.config.activate.on-profile=development
server.port=9001
#---
spring.config.activate.on-profile=production
server.port=0
server:
port: 9000
---
spring:
config:
activate:
on-profile: "development"
server:
port: 9001
---
spring:
config:
activate:
on-profile: "production"
server:
port: 0
在前面的示例中,默认端口是 9000。然而,如果名为 ‘development’ 的 Spring profile 处于激活状态,则端口为 9001。如果 ‘production’ 处于激活状态,则端口为 0。
文档按照遇到的顺序进行合并。后面的值会覆盖前面的值。
发现外部属性的内置选项
Spring Boot 在运行时将来自 application.properties(或 YAML 文件及其他位置)的外部属性绑定到应用程序中。由于支持的属性可能来自 classpath 中额外的 jar 文件,因此(从技术上讲也不可能)无法在单一位置提供一份完整详尽的支持属性列表。
一个启用了 Actuator 功能的运行中应用程序具有一个 configprops 端点,该端点展示了所有通过 @ConfigurationProperties 可绑定和已绑定的属性。
附录包含了一个 application.properties 示例,列出了 Spring Boot 支持的最常见属性。完整的属性列表可以通过在源代码中搜索 @ConfigurationProperties 和 @Value 注解,以及偶尔使用 Binder 来获得。有关属性加载顺序的详细信息,请参阅 Externalized Configuration。