相对于在项目构建配置中硬编码某些配置,你可以使用已存在的构建配置自动暴露它们,Maven和Gradle都支持。
你可以使用Maven的资源过滤(resource filter)自动暴露来自Maven项目的属性,如果使用spring-boot-starter-parent
,你可以通过@..@
占位符引用Maven项目的属性,例如:
[email protected]@
[email protected]@
注 如果启用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占位符(比如${foo}
)且没有将useDefaultDelimiters
属性设置为false
,那构建时这些属性将被暴露出去。
你可以通过配置Java插件的processResources
任务自动暴露来自Gradle项目的属性:
processResources {
expand(project.properties)
}
然后你可以通过占位符引用Gradle项目的属性:
app.name=${name}
app.description=${description}
注 Gradle的expand
方法使用Groovy的SimpleTemplateEngine
转换${..}
占位符,${..}
这种格式跟Spring自身的属性占位符机制冲突,想要自动暴露Spring属性占位符,你需要将其进行编码,比如\${..}
。
SpringApplication已经被属性化(主要是setters),所以你可以在创建应用时使用它的Java API修改其行为,或者使用以spring.main.*
为key的属性来外部化这些配置。比如,在application.properties
中可能会有以下内容:
spring.main.web-environment=false
spring.main.banner-mode=off
这样,Spring Boot在启动时将不会显示banner,并且该应用也不是一个web应用。
注 以上示例也展示在属性名中使用下划线(_
)和中划线(-
)的灵活绑定。
外部配置定义的属性会覆盖创建ApplicationContext
时通过Java API指定的值,让我们看如下应用:
new SpringApplicationBuilder()
.bannerMode(Banner.Mode.OFF)
.sources(demo.MyApp.class)
.run(args);
并使用以下配置:
spring.main.sources=com.acme.Config,com.acme.ExtraConfig
spring.main.banner-mode=console
实际的应用将显示banner(被配置覆盖),并为ApplicationContext
指定3个sources,依次为:demo.MyApp
,com.acme.Config
,com.acme.ExtraConfig
。
默认情况下,来自不同源的属性以一个定义好的顺序添加到Spring的Environment
中(精确顺序可查看'Sprin Boot特性'章节的Chapter 24, Externalized Configuration)。
为应用程序源添加@PropertySource
注解是一种很好的添加和修改源顺序的方法。传递给SpringApplication
静态便利设施(convenience)方法的类和使用setSources()
添加的类都会被检查,以查看它们是否有@PropertySources
,如果有,这些属性会被尽可能早的添加到Environment
里,以确保ApplicationContext
生命周期的所有阶段都能使用。以这种方式添加的属性优先级低于任何使用默认位置(比如application.properties
)添加的属性,系统属性,环境变量或命令行参数。
你也可以提供系统属性(或环境变量)来改变该行为:
spring.config.name
(SPRING_CONFIG_NAME
)是根文件名,默认为application
。spring.config.location
(SPRING_CONFIG_LOCATION
)是要加载的文件(例如,一个classpath资源或URL)。Spring Boot为该文档设置一个单独的Environment
属性,它可以被系统属性,环境变量或命令行参数覆盖。不管你在environment设置什么,Spring Boot都将加载上面讨论过的application.properties
。如果使用YAML,那具有.yml
扩展的文件默认也会被添加到该列表,详情参考ConfigFileApplicationListener
有些人喜欢使用(例如)--port=9000
代替--server.port=9000
来设置命令行配置属性。你可以通过在application.properties
中使用占位符来启用该功能,比如:
server.port=${port:8080}
注 如果你继承自spring-boot-starter-parent
POM,为了防止和Spring格式的占位符产生冲突,maven-resources-plugins
默认的过滤令牌(filter token)已经从${*}
变为@
(即@maven.token@
代替${maven.token}
)。如果直接启用maven对application.properties
的过滤,你可能想使用其他的分隔符替换默认的过滤令牌。
注 在这种特殊的情况下,端口绑定能够在一个PaaS环境下工作,比如Heroku和Cloud Foundry,因为在这两个平台中PORT
环境变量是自动设置的,并且Spring能够绑定Environment
属性的大写同义词。
YAML是JSON的一个超集,可以非常方便的将外部配置以层次结构形式存储起来,比如:
spring:
application:
name: cruncher
datasource:
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost/test
server:
port: 9000
创建一个application.yml
文件,将它放到classpath的根目录下,并添加snakeyaml
依赖(Maven坐标为org.yaml:snakeyaml
,如果你使用spring-boot-starter
那就已经包含了)。一个YAML文件会被解析为一个Java Map<String,Object>
(和一个JSON对象类似),Spring Boot会平伸该map,这样它就只有1级深度,并且有period-separated的keys,跟人们在Java中经常使用的Properties
文件非常类似。
上面的YAML示例对应于下面的application.properties
文件:
spring.application.name=cruncher
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost/test
server.port=9000
查看'Spring Boot特性'章节的Section 24.6, “Using YAML instead of Properties”可以获取更多关于YAML的信息。
Spring Environment
有一个API可以设置生效的profiles,但通常你会通过系统属性(spring.profiles.active
)或OS环境变量(SPRING_PROFILES_ACTIVE
)设置。比如,使用一个-D
参数启动应用程序(记着把它放到main
类或jar文件之前):
$ java -jar -Dspring.profiles.active=production demo-0.0.1-SNAPSHOT.jar
在Spring Boot中,你也可以在application.properties
里设置生效的profile,例如:
spring.profiles.active=production
通过这种方式设置的值会被系统属性或环境变量替换,但不会被SpringApplicationBuilder.profiles()
方法替换。因此,后面的Java API可用来在不改变默认设置的情况下增加profiles。
想要获取更多信息可查看'Spring Boot特性'章节的Chapter 25, Profiles。
一个YAML文件实际上是一系列以---
线分割的文档,每个文档都被单独解析为一个平坦的(flattened)map。
如果一个YAML文档包含一个spring.profiles
关键字,那profiles的值(以逗号分割的profiles列表)将被传入Spring的Environment.acceptsProfiles()
方法,并且如果这些profiles的任何一个被激活,对应的文档被包含到最终的合并中(否则不会)。
示例:
server:
port: 9000
---
spring:
profiles: development
server:
port: 9001
---
spring:
profiles: production
server:
port: 0
在这个示例中,默认的端口是9000
,但如果Spring profile development
生效则该端口是9001
,如果production
生效则它是0
。
YAML文档以它们出现的顺序合并,所以后面的值会覆盖前面的值。
想要使用profiles文件完成同样的操作,你可以使用application-${profile}.properties
指定特殊的,profile相关的值。
Spring Boot在运行时会将来自application.properties
(或.yml
)的外部属性绑定到应用,因为不可能将所有支持的属性放到一个地方,classpath下的其他jar也有支持的属性。
每个运行中且有Actuator特性的应用都会有一个configprops
端点,它能够展示所有边界和可通过@ConfigurationProperties
绑定的属性。
附录中包含一个application.properties示例,它列举了Spring Boot支持的大多数常用属性,查看@ConfigurationProperties
,@Value
,还有不经常使用的RelaxedEnvironment
的源码可获取最权威的属性列表。