本文属于原创,转载注明出处,欢迎关注微信小程序 小白AI博客
微信公众号 小白AI
或者网站 xiaobaiai.net 或者我的CSDN blog.csdn.net/freeape
[TOC]
进入实际项目开发中,我们不仅仅是靠着默认的全局配置文件 application.properties
来配置我们的项目了,Spring Boot中的配置文件也有不少需要注意的地方,掌握后,可以方便的让我们在做项目中游刃于各种配置了,让配置一目了然,层次清楚,模块清晰,写成总结,另外方便以后参考查阅。该文章的内容是最新的配置文件介绍内容,全部参考最新的官方文档所写,截至2019年11月21日,此时Spring是 5.2.1
版本,Spring Boot是 2.2.1
版本。
Spring Boot
提供了一个 spring-boot-devtools
jar包,提供了一些方便程序开发的功能,主要是监控程序的变化,然后进行自动重新启动。使用 spring-boot-devtools
需要在 pom.xml
中添加依赖项,同时需要设置
。 spring-boot-devtools
默认将只在 开发环境
生效,通过 Spring Boot
插件打包时默认是不会包含 spring-boot-devtools
。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency>复制代码
创建一个 Spring Boot
项目后,会在 src/main/resources
目录下默认生成一个全局配置文件 application.properties
,不过里面啥内容也没有。Spring Boot已经将所有默认配置参数都自动配置好了(https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html),如果我们在外部配置文件中修改配置,则默认配置参数就会被修改(Externalized Configuration, 配置外部化 ),配置外部化的方式有好几种,可以使用属性文件(properties file)、YAML文件、环境变量和命令行参数将配置外部化,下面内容会详细介绍。
比如配置文件可以是 application.properties
或者是 application.yml
,都可以配置,只是里面的配置语法不一样而已,yml格式层次相比properties格式要分明些。
.properties
写法:
server.port = 9090 spring.application.name = demoservice复制代码
.yml
写法:
spring: application: name: demoservice server: port: 9090复制代码
注意:yml格式中一定不要用制表符tab,冒号和值之间一定要有空格。
Spring Boot对参数的重写(覆盖)有一个顺序,这是我们需要注意的,这里概况如下:
Devtools
时, $HOME/.config/spring-boot
文件夹中的Devtools全局设置属性 @TestPropertySource
针对对测试的注解 properties
。在 @SpringBootTest
和测试注释中提供,用于测试应用程序的特定部分 SPRING_APPLICATION_JSON
(内嵌在环境变量或系统属性中的JSON)的属性 ServletConfig
初始化参数 ServletContext
初始化参数 java:comp/env
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
指定) 举一个具体的例子来说明上述的顺序是如何生效的:
import org.springframework.stereotype.*; import org.springframework.beans.factory.annotation.*; @Component public class MyBean { @Value("${name}") private String name; // ... }复制代码
比如在应用程序类路径(例如,打包 在jar内
)上,可以有一个 application.properties
文件,该文件为 name
属性设置了默认属性值。在新环境中运行时,可以 在jar外部
提供 application.properties
文件,该文件覆盖会覆盖 在jar内
的 application.properties
。又如对于一次性测试,可以使用特定的命令行开关启动(例如, java -jar app.jar --name="Spring"
)也可以覆盖 name
属性值。又如可以JSON格式环境变量 $ java -Dspring.application.json='{"name":"test"}' -jar myapp.jar
来覆盖。其他方式就不一一举例了。
参数设置有两种方式语法,一个 properties
,一个是 yml
, SpringApplication
从 application.properties
文件加载以下位置的属性,并将它们添加到 Spring环境
中。
config config
上述列表按优先级排序(在列表中较高位置定义的属性将覆盖在较低位置定义的属性,如1中设置的属性值将覆盖2中同属性的属性值)。
注意:用maven构建项目时,src/main/resources目录就是默认的classpath
另外这里说下yml的注意点和特殊用法。
一定要有空格
一定要有空格
一定要有空格
# 下面会输出得到hello换行xiaobaiai.net name: "hello/nxiaobaiai.net" # 下面会输出得到hello/nxiaobaiai.net name: 'hello/nxiaobaiai.net'复制代码
new Date('1976-07-31')
) # 对象行内写法 students: { name: Steve, age: 22 } # 数组行内写法 animal: [Cat, Dog] # 或者数组非行内写法 animal: - Cat - Dog复制代码
生成配置参数随机值在测试或者某些场景下是非常有用的。
如我们配置:
#random int app.location-x=${random.int} app.location-y=${random.int} #random int with max app.user-age=${random.int(100)} #random int range app.max-users=${random.int[1,10000]} #random long with max app.refresh-rate-milli=${random.long(1000000)} #random long range app.initial-delay-milli=${random.long[100,90000000000000000]} #random 32 bytes app.user-password=${random.value} #random uuid. Uses java.util.UUID.randomUUID() app.instance-id=${random.uuid}复制代码
最后输出: locationX=-449689812, locationY=-2048116572, userAge=88, maxUsers=8927, refreshRateMilli=418859, initialDelayMilli=12542150790115755, userPassword=95ea8b43fd16dc26aad0030c1340e723, instanceId=bd252902-54e9-47b3-bebf-a81b1300ff69
在配置参数中可以通过占位符来实现引用之前定义的参数值,如:
app.name=MyApp app.description=${app.name} is a Spring Boot application复制代码
有些人喜欢(例如)使用 --port=9000
而不是 --server.port=9000
在命令行上设置配置属性。可以通过在 application.properties
中使用 占位符
来启用此行为:
server.port=${port:8080}复制代码
注意:如果继承自 spring-boot-starter-parent
POM,则maven资源插件的默认筛选标记已从 ${*}
更改为 @
(即, @maven.token@
而不是 ${maven.token}
),以防止与spring样式占位符冲突。如果直接为 application.properties
启用了Maven筛选,则可能还需要将默认筛选标记更改为其他分隔符,而不是 @
。
如果不喜欢将 application.properties
作为配置文件名,可以通过指定 spring.config.name
环境属性切换到另一个文件名。还可以使用 spring.config.location
环境属性(目录位置或文件路径的逗号分隔列表)指定配置文件位置。以下示例演示如何指定其他文件名:
$ java -jar myproject.jar --spring.config.name=myConfig复制代码
下面的示例演示如何指定两个位置:
$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties复制代码
如果 spring.config.location
包含目录(而不是文件),则需要以 /
结尾,并且,运行的时候,在加载配置之前,应该附加从 spring.config.name
配置的名称或者默认配置名称。默认不配置 spring.config.location
则搜索配置文件顺序为:
file:./config/ file:./ classpath:/config/ classpath:/复制代码
使用时配置自定义配置位置时 spring.config.location
,它们会替换默认位置。例如,如果 spring.config.location
配置了值 classpath:/custom-config/,file:./custom-config/
,则搜索顺序将变为:
file:./custom-config/ classpath:custom-config/复制代码
当使用配置自定义配置位置时 spring.config.additional-location
,除了额外配置路径外,还会使用默认位置。在默认位置之前搜索其他位置。
注意:在编程环境中,直接去application.properties中设置spring.config.name是无法生效的,只有在命令行或者设置环境变量 export SPRING_CONFIG_NAME=myConfig
,或则在代码中去手动编码导入指定路径中的配置文件。
直接通过编码加载指定配置文件去实现,这种方式其实跟后面小节讲到的自定义属性是相通的,只多了一个指定文件名的注解,更详细的可以看后面操作。比如我们创建 test.properties
,路径跟也放在 src/main/resources
下面:
my.app.name=hello my.app.func=test复制代码
然后新建一个参数Bean:
@Configuration @ConfigurationProperties(prefix="my.app") @PropertySource("classpath:test.properties") public class ConfigTestBean { private String name; private String func; // 省略getter和setter }复制代码
这样就Ok了,怎么是验证可以看自定义配置参数小节。
默认情况下, SpringApplication
将任何命令行选项参数(即以 --
开头的参数,例如 --server.port=9000
)转换为属性,并将它们添加到 Spring环境
中。如前所述,命令行属性顺序排在第四,始终优先于其下面属性源。
如果不希望命令行属性添加到Spring 环境
中,可以在程序中使用 SpringApplication.setAddCommandLineProperties(false)
禁用它们。
除了 application.properties
文件外,还可以使用以下命名约定定义特定于配置文件的属性: application-{profile}.properties
。环境有一组默认配置文件(默认情况下profile为default,即application-default.properties),如果未设置活动配置文件,则使用默认的 application-default.properties
文件,加载顺序和优先级还是与 application.properties
一样的。 Spring
可使用Profile决定程序在不同环境下执行情况,包含配置、加载Bean、依赖等, Spring
的Profile一般项目包含:dev(开发), test(单元测试), qa(集成测试), prod(生产环境)。同样地,Maven也有Profile配置,可在构建过程中针对不同的Profile环境执行不同的操作,包含配置、依赖、行为等,每个Profile中可设置:id(唯一标识), properties(配置属性), activation(自动触发的逻辑条件), dependencies(依赖)等。
说到这里,如何激活profile呢?下面介绍三种方式。
注意:application-{profile}.properties的重写优先级是要高于application.properties的,这个跟配置文件 加载顺序
没有关系。另外创建application-{profile}.yml文件跟properties是一样的。
在配置文件中设置,这种方式不灵活,实际开发中不不太会用到
spring.profiles.active=test复制代码
使用占位符,在打包时替换,以Maven为例
第一步 在properties中添加(package.target是自定义的参数):
spring.profiles.active=@package.target@复制代码
第二步 在pom.xml中增加不同环境打包的配置:
<!-- 与Maven build标记并列 --> <profiles> <!-- 开发环境 --> <profile> <id>dev</id> <activation> <activeByDefault>true</activeByDefault> </activation> <properties> <package.target>dev</package.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </dependency> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jdbc</artifactId> </dependency> </dependencies> </profile> <!-- 生产环境 --> <profile> <id>prod</id> <properties> <package.target>prod</package.target> </properties> </profile> </profiles>复制代码
从上面的配置可以看出,Maven的Profile配置了两个:dev和prod,并且在dev中使用了内嵌Tomcat,而 prod 中没有(这种配置场景如生产环境下使用外部Tomcat,开发时使用内部Tomcat)。
第三步 再添加资源过滤实现在构建时修改以“@xxx@”表示的属性,利用Maven的resources插件:
... <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> <!-- Maven build标记内 --> <resources> <!-- 不加该resource也可以 --> <resource> <directory>src/main/resources</directory> <excludes> <!-- 排除掉src/main/resources下的所有application*.properties文件 --> <exclude>application*.properties</exclude> </excludes> </resource> <resource> <!-- 指定要处理的资源目录 --> <directory>src/main/resources</directory> <!-- 是否替换@xx@表示的maven properties属性值 --> <filtering>true</filtering> <includes> <!-- 将文件内容的“@xx@”替换为相应的变量,即package.target --> <include>application-${package.target}.properties</include> </includes> </resource> </resources>复制代码
第四步 就是编译打包了:
# 根据Maven Profile的 dev 构建环境包 $ mvn clean package -Dmaven.test.skip=true -Pdev复制代码
通过设置系统环境变量:
export SPRING_PROFILES_ACTIVE=dev复制代码
Java命令行设定方式:
# 方式一 $ java -jar app.jar --spring.profiles.active=dev # 方式二 $ java -jar -Dspring.profiles.active=dev demo-0.0.1-SNAPSHOT.jar复制代码
注解方式( @ActiveProfiles
是Spring Boot的Test starter提供的注解,在单元测试中就比较有用了,只能在 /src/test/java
中使用):
@ActiveProfiles("dev")复制代码
YAML文件实际上可以是由 ---
行分隔的一系列文档,每个文档被分别解析为一个展开的配置映射。然后激活dev还是production的方式同样的也有指定环境变量或者命令行方式之类的。
# 通用属性 server: port: 9000 --- # dev环境下配置 spring: profiles: dev server: port: 9001 --- # production生产环境下配置 spring: profiles: production server: port: 0复制代码
Spring
已经为我们提供很多的默认参数,不过我们也可以创建自己的配置参数。比如我们在 application.properties
中创建下面的自定义属性:
#random int app.location-x=${random.int} app.location-y=${random.int} #random int with max app.user-age=${random.int(100)} #random int range app.max-users=${random.int[1,10000]} #random long with max app.refresh-rate-milli=${random.long(1000000)} #random long range app.initial-delay-milli=${random.long[100,90000000000000000]} #random 32 bytes app.user-password=${random.value} #random uuid. Uses java.util.UUID.randomUUID() app.instance-id=${random.uuid}复制代码
然后创建对应的Java参数组件 MyAppProperties.java
:
@Component @ConfigurationProperties("app") public class MyAppProperties { private int locationX; private int locationY; private int userAge; private int maxUsers; private long refreshRateMilli; private long initialDelayMilli; private String userPassword; private UUID instanceId; public int getLocationX() { return locationX; } public void setLocationX(int locationX) { this.locationX = locationX; } public int getLocationY() { return locationY; } public void setLocationY(int locationY) { this.locationY = locationY; } public int getUserAge() { return userAge; } public void setUserAge(int userAge) { this.userAge = userAge; } public int getMaxUsers() { return maxUsers; } public void setMaxUsers(int maxUsers) { this.maxUsers = maxUsers; } public long getRefreshRateMilli() { return refreshRateMilli; } public void setRefreshRateMilli(long refreshRateMilli) { this.refreshRateMilli = refreshRateMilli; } public long getInitialDelayMilli() { return initialDelayMilli; } public void setInitialDelayMilli(long initialDelayMilli) { this.initialDelayMilli = initialDelayMilli; } public String getUserPassword() { return userPassword; } public void setUserPassword(String userPassword) { this.userPassword = userPassword; } public UUID getInstanceId() { return instanceId; } public void setInstanceId(UUID instanceId) { this.instanceId = instanceId; } @Override public String toString() { return "MyAppProperties [locationX=" + locationX + ", locationY=" + locationY + ", userAge=" + userAge + ", maxUsers=" + maxUsers + ", refreshRateMilli=" + refreshRateMilli + ", initialDelayMilli=" + initialDelayMilli + ", userPassword=" + userPassword + ", instanceId=" + instanceId + "]"; } }复制代码
@ConfigurationProperties
注解向 Spring Boot
声明该类中的所有属性和配置文件中相关的配置进行绑定。 prefix = "app"
( prefix=可省略
) : 声明配置前缀,将该前缀下的所有属性进行映射。 @Component
或者 @Configuration
:将该组件加入 Spring Boot
容器,只有这个组件是容器中的组件,配置才生效。
提示:也可以通过 @Value("${key}")
读取配置文件中的属性, key = properties
文件等号左边的key部分。在我们定义的 Java 参数组件中,还可以对具体的参数进行注解断言,如@Email加到邮件的变量上,则如果注入的不是一个合法的邮件地址则会抛出异常。这类注解还有 @AssertFalse
校验false、 @AssertTrue
校验true、 @DecimalMax(value=10,inclusive=true)
小于等于10,inclusive=true,是小于等于、 @DecimalMin(value=,inclusive=)
、 @Max(value=)
小于等于value、 @Min(value=)
大于等于value、 @Past
检查日期、 @Pattern(regex=,flag=)
正则、 @Validate
对po实体类进行校验等。
最后还需要加入依赖 spring-boot-configuration-processor
:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <!-- 加入spring-boot-configuration-processor --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>复制代码
校验我们自定义的配置:
@SpringBootApplication public class Test07HelloworldApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(Test07HelloworldApplication.class, args); MyAppProperties bean = context.getBean(MyAppProperties.class); System.out.println(bean.toString()); } } // output // MyAppProperties [locationX=1329054364, locationY=1100464591, userAge=99, maxUsers=8007, refreshRateMilli=733281, initialDelayMilli=54489880705550952, userPassword=76aebd15270f7065adf3d31b5a790829, instanceId=681ed3a4-a561-460c-b826-58229c31b055]复制代码
上述的内容大部分经过实际Demo验证,示例代码可以在 github.com/yicm/Spring… 上找到。配置文件这一章细节内容比较多,但是我们把我几个点就好了,这个总结下:
application.properties(yml) application-{profile}.properties(yml)
如果你知道了上述总结的具体内容,那么这一博文你也差不多都了解了。
本文属于原创,转载注明出处,欢迎关注CSDN freeape 或微信小程序 小白AI博客
微信公众号 小白AI
或者网站 xiaobaiai.net