SpringBoot允许使用配置文件对应用程序进行配置,支持以下不同形式的配置源:
- 属性文件(比如application.properties)
- yaml文件(后缀可以是yml或者yaml)
- 环境变量
- 命令行参数
获取这些外部化属性有以下几种方式:
- 使用@Value注解
- 使用Spring的Environment抽象层进行访问
- 使用@ConfigurationProperties注解将一批特定属性绑定到java对象
配置源的加载顺序和优先级
由于先加载的配资源都有可能被后加载的配资源覆盖,因此认为后加载的配置源优先级更高,加载顺序如下:
- 默认属性(通过SpringApplication.setDefaultProperties()方法指定)
- 配置类(@Configuration修饰的类)上用@PropertySource注解加载的属性文件中的属性值
- 配置数据(如application.properties文件等)
- RandomValuePropertySource,只包含random.*中的属性
- 操作系统环境变量
- java系统属性(System的getProperties()方法返回的属性)
- 来自java:comp/env的jndi属性(只在Web服务器或应用服务器中有用)
- ServletContext的初始化参数(在Web.xml文件中通过元素设置的初始化参数)(只在Web服务器或应用服务器中有用)
- ServletConfig的初始化参数(在Web.xml文件中通过元素设置的初始化参数,或者通过@Servlet注解设置的初始化参数)
- 来自SPRING_APPLICATION_JSON的属性(嵌套在环境变量或系统属性中的JSON文本)
- 命令行参数
- 测试用例类上通过@SpringBootTest注解的properties所指定的属性(仅在单元测试生效)
- 测试用例类上用@TestPropertySource注解加载的属性文件中的属性值(仅在单元测试生效)
- 当SpringBoot的devtools工具处于激活状态时,用户Home目录中.config/spring-boot/子目录下spring-boot-devtools.properties或spring-boot-devtools.yml文件中设置的属性值(windows平台对应“C:\User\用户名”下的配置文件)
此外application.properties(包括application.yml)也有几个不同的来源,它们按如下顺序加载:
- jar包内的application.properties(或application.yml)
- jar包内的application-{profile}.properties(或application-{profile}.yml)
- jar包外临时指定的application.properties(或application.yml)
- jar包外临时指定的application-{profile}.properties(或application-{profile}.yml)
jar包外临时指定的配置文件优先级高于jar包内;特定的profile对应的配置文件优先级高于通用配置文件的优先级。
利用JSON参数配置
SpringBoot支持一个特殊的系统属性(环境变量):Spring.application.json,通过这个属性可传入一段json文本,而这段文本会被解析成配置属性来加载,加载顺序排在第10位(上一小节)。- @SpringBootApplication
- public class App
- {
- public static void main(String[] args)
- {
- // 设置spring.application.json系统属性
- // 属性值为{“fkjava”:{name:""SPringBoot服务器", age:20, servers:["fkjava.org", "crazyit.org"]}}
- System.setProperty("spring.application.json",
- "{"fkjava":{"name":"SPringBoot服务器", "age":20, " +
- ""servers":["fkjava.org", "crazyit.org"]}}");
- SpringApplication.run(App.class, args);
- }
- }
复制代码 application.properties文件内容:- fkjava.name=springboot软件服务器
- fkjava.age=35
复制代码- @RestController
- public class HelloController {
- // 使用@Value注解访问配置属性
- @Value("${fkjava.name}")
- private String name;
- @Value("${fkjava.age}")
- private String age;
- @Value("${fkjava.servers[0]}")
- private String server1;
- @Value("${fkjava.servers[1]}")
- private String server2;
- @GetMapping
- public Map<String, String> hello()
- {
- return Map.of("名称", name, "年龄", age,
- "服务器1", server1, "服务器2", server2);
- }
- }
复制代码 输出结果:
可见,通过spring.application.json设置的属性覆盖了application.properties文件配置的属性。
使用YAML配置文件
application.properties文件的另一种形式是application.yml,这两种文件形式不同,本质一样。
YAML是JSON格式的超集,以层次格式来存储配置属性,SpringBoot使用SnakeYAML来解析YAML文件,由于spring-boot-starter自动依赖SnakeYAML,因此只要项目添加了spring-boot-starter依赖,SpringApplication就能解析YAML文件。
application.properties文件中的点号(.)对应yaml文件中的缩进,比如spring.application,name=cruncher对应于- spring:
- application:
- name: "cruncher"
复制代码 如果YAML配置的属性包含多个列表项,那么它会被转化成【index】形式,比如- fkjava:
- name: "SpringBoot软件"
- age: 20
- servers:
- - www.fkjava.org
- - www.crazyit.org
复制代码 被转换为:
fkjava.servers[0]=www.fkjava.org
fkjava.servers[1]=www.crazyit.org
如果程序要加载YAML文件配置的属性,可使用以下工具类
- YamlPropertiesFactoryBean,它将YAML文件加载为Properties对象
- YamlMapFactoryBean,它将YAML文件加载为Map对象
- YamlPropertySourceLoader,它将YAML文件加载为PropertySource.
@PropertySource和@TestPropertySource都只能加载属性文件,不能加载Yaml文件,这是Yaml文件的局限之一。
文件路径:/resources/application.yml(系统会自动加载)- fkjava:
- server:
- name: "疯狂软件服务器"
- port: 9000
复制代码 文件路径:/resources/fk/fk.yml(系统不会自动加载)- fkjava:
- name: "疯狂软件"
- age: 20
- servers:
- - www.fkjava.org
- - www.crazyit.org
复制代码- //定义一个配置环境后处理器来加载fk.yml
- public class FkEnvironmentPostProcessor implements EnvironmentPostProcessor
- {
- // 创建YamlPropertySourceLoader,用于加载YAML文件
- private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
- @Override
- public void postProcessEnvironment(ConfigurableEnvironment environment,
- SpringApplication application)
- {
- // 指定自定义的配置文件
- Resource path = new ClassPathResource("fk/fk.yml");
- // 加载自定义配置文件
- PropertySource<?> ps = null;
- try
- {
- ps = this.loader.load("custom-resource", path).get(0);
- }
- catch (IOException e)
- {
- e.printStackTrace();
- }
- System.out.println("fkjava.name: " + ps.getProperty("fkjava.name"));
- System.out.println("fkjava.age: " +ps.getProperty("fkjava.age"));
- System.out.println("fkjava.servers[0]: " +ps.getProperty("fkjava.servers[0]"));
- System.out.println("fkjava.servers[1]: " +ps.getProperty("fkjava.servers[1]"));
- // 将PropertySource中的属性添加到Environment配置环境中
- environment.getPropertySources().addLast(ps);
- }
- }
复制代码 可通过/META-INF/spring.factories来注册配置环境后处理器:- org.springframework.boot.env.EnvironmentPostProcessor=org.crazyit.app.FkEnvironmentPostProcessor
复制代码 这样一来application.yml和fk.yml都被加载进来,下来可以在其他任何Bean中通过@Value来访问它们- @RestController
- public class HelloController
- {
- // 使用@Value注解访问配置属性
- @Value("${fkjava.server.name}")
- private String serverName;
- @Value("${fkjava.server.port}")
- private String serverPort;
- @Value("${fkjava.age}")
- private String age;
- @GetMapping
- public String hello()
- {
- return "名称: " + serverName + ", 端口: " + serverPort
- + ", 年龄: " + age;
- }
- }
复制代码 如果仅需要加载自定义的Yaml文件,在组件中使用这些配置属性,并不需要将属性添加到配置环境中,那么只要在容器中配置一个YamlPropertiesFactoryBean工厂Bean或YamlMapFactoryBean工厂Bean,它们就会自动读取Yaml文件,将其中的配置内容加载为Properties对象或Map对象。- @Configuration
- public class MyConfig
- {
- // 在容器中配置一个YamlPropertiesFactoryBean
- @Bean
- public YamlPropertiesFactoryBean fkProps()
- {
- var factory = new YamlPropertiesFactoryBean();
- factory.setResources(new ClassPathResource("fk/fk.yml"));
- return factory;
- }
- }
复制代码 spring中的工厂Bean有一个特征:当程序通过spring容器获取工厂Bean时,实际获取到的是该工厂的产品(getObject()方法的返回值),因此当程序获取上面配置的fkProps时,实际返回的是一个Properties对象。- @RestController
- public class HelloController
- {
- // 使用@Value注解访问配置属性
- @Value("${fkjava.server.name}")
- private String serverName;
- @Value("${fkjava.server.port}")
- private String serverPort;
- // 指定将容器中fkProps Bean注入fkProps实例变量
- @Resource(name = "fkProps")
- private Properties fkProps;
- @GetMapping
- public String hello()
- {
- return "名称: " + serverName + ", 端口: " + serverPort
- + ", 年龄: " + fkProps.getProperty("fkjava.age");
- }
- }
复制代码 改变配置文件的位置
默认情况下,SpringBoot或按如下顺序加载配置文件,后加载的文件会覆盖先加载的文件,因此,后加载的文件有更高的优先级
- 类加载路径的根路径
- 类加载路径下的/config子目录
- 当前路径
- 当前路径的/config子目录
- 当前路径的/config子目录的任意直接子目录,比如/config/abc、/config/aef等
如果想改变这种默认行为,可通过如下系统属性(或环境变量、或命令行参数)来设置
- spring.config.name:改变配置文件的文件名,默认是application。如果用OS环境变量来设置,则属性对应于SPRING_APPLICATION_NAME环境变量名。
- spring.config.location:改变配置文件的加载路径。如果用OS环境变量来设置,则属性对应于SPRING_APPLICATION_LOCATION环境变量名。
- spring.config.additional.location:添加配置文件的加载路径,不会覆盖原来的配置文件的加载路径。
不要使用SpringBoot配置属性来设置以上三种属性,因为这几个属性的加载实际非常早,只能通过系统环境变量、系统属性或命令行参数来设置。
通过spring.config.location或spring.config.additional.location指定的加载路径是有先后顺序的,比如spring.config.location设置为“optional:classpath:/fkjava/,optional:file:./fkit/”,那么加载顺序为:
- optional:classpath:/fkjava/
- optional:file:./fkit/
如果使用spring.config.additional.location来添加配置文件的加载路径,那么新增路径总是排在默认的加载路径之后。比如将spring.config.additional.location设置为“optional:classpath:/fkjava/,optional:file:./fkit/”,那么SpringBoot加载顺序为:
- optional:classpath:/(类加载路径的根路径)
- optional:classpath:/config/(类加载路径下的/config子目录)
- optional:file:./(当前路径)
- optional:file:./config/(当前路径的/config子目录)
- optional:file:./config/*/(当前路径的/config子目录的任意直接子目录,比如/config/abc、/config/aef等)
- optional:classpath:/fkjava/
- optional:file:./fkit/
前5项是SpringBoot配置文件的默认加载路径
通配符(*)只能在外部路径中使用,例如file前缀就表示使用文件系统的当前路径;classpath前缀的路径不能使用通配符
每个加载路径只能在最后面使用一个通配符- @SpringBootApplication
- public class App
- {
- static {
- // 设置配置文件的文件名
- // 通过系统属性设置SpringBoot配置文件的主文件名可以是application和fk
- // 这样SpringBoot就会自动加载application.yml和fk.yml两个配置文件
- System.setProperty("spring.config.name", "application, fk");
- // 设置配置文件的加载路径
- // optional:表示如果classpath下没有指定的配置文件,则不报错,如果不加这个前缀,若该路径下不存在配置文件,就会抛出异常
- System.setProperty("spring.config.location",
- "classpath:/, optional:classpath:/fk/");
- // 设置额外的加载路径
- // System.setProperty("spring.config.additional-location",
- // "optional:classpath:/fk/");
- }
- public static void main(String[] args)
- {
- // 创建Spring容器、运行Spring Boot应用
- SpringApplication.run(App.class, args);
- }
- }
复制代码 导入额外的配置文件
在spring容器刷新之后,SpringBoot还可使用如下方式导入额外的配置文件
- 使用@PropertySource导入额外的属性文件
- 使用spring.config.import导入额外的配置文件(包括属性文件和Yaml文件)
如果只是为应用中的Bean组件导入一些配置属性,完全可通过上面两种方式来导入。以下示例:
resources\fk\fk.yml文件内容:(只能通过spring.config.import导入)- fkjava:
- name: "疯狂软件"
- age: 25
- servers:
- - www.fkjava.org
- - www.crazyit.org
复制代码 resources\fk\crazyit.properties文件内容:(spring.config.import和@PropertySource都能导入)- crazyit.book.name=Spring Boot
- crazyit.book.price=128
复制代码 resources\applocation.yml文件内容:- fkjava:
- server:
- name: "疯狂软件服务器"
- port: 9000spring: config: # 指定导入类加载路径下fk/fk.yml文件 import: optional:classpath:/fk/fk.yml
复制代码 通过@PropertySource导入crazyit.properties文件示例:- @SpringBootApplication
- // 导入类加载路径下fk/crazyit.properties文件
- @PropertySource("classpath:/fk/crazyit.properties")
- public class App
- {
- public static void main(String[] args)
- {
- // 创建Spring容器、运行Spring Boot应用
- SpringApplication.run(App.class, args);
- }
- }
复制代码 使用占位符
配置文件中可使用占位符(${})来引用已定义的属性,或者引用其他配置源(系统属性、环境变量、命令参数等)配置的属性。示例如下:
resources\applocation.yml文件内容:- app:
- name: "占位符"
- # 引用配置文件中的配置属性
- description: "${app.name}应用演示了如何在配置文件中使用占位符"
- book:
- # 引用外部的配置属性
- description: ${book.name}是一本非常优秀的图书
- server:
- # 配置服务端口
- port: ${port}
复制代码 添加命令行参数:--book.name="哈利波特" --port=9090,然后启动应用就会生效。
读取构建文件的属性
SpringBoot允许配置文件读取构建文件(pom.xml或build.gradle)的属性.
只要在pom.xml文件中定义如下元素,就能在配置文件中通过“@属性名@”来引用pom.xml文件中的属性- <parent>
- <groupId>org.springframework.boot</groupId>
- spring-boot-starter-parent</artifactId>
- <version>2.4.2</version>
- </parent>
复制代码 resources\applocation.yml文件内容:- app:
- java:
- # 引用pom.xml文件中的属性
- version: @java.version@
- sourceEncoding: @project.build.sourceEncoding@
- name: @name@
- version: @version@
复制代码 对于Gradle项目,首先要在build.gradle中对java插件的processResources进行如下配置,然后将这段配置加到build.gradle文件的最后。- // 配置Java插件的processResources Task
- processResources {
- expand(project.properties)
- }
复制代码 接下来即可在配置文件中通过“${属性名}”(这里不再是占位符的表示)的形式引用build.gradle中属性。
resources\applocation.yml文件内容:- app:
- java:
- version: "${sourceCompatibility}"
- name: "${rootProject.name}"
- version: "${version}"
复制代码 配置随机值
如果需要为应用配置各种随机值(如随机整数、uuid等),可通过在配置文件中使用${random.xxx}的形式来生成随机值。示例如下:
resources\applocation.yml文件内容:- fkjava:
- secret: "${random.value}"
- number: "${random.int}"
- bignumber: "${random.long}"
- uuid: "${random.uuid}"
- number-less-than-ten: "${random.int(10)}"
- number-in-range: "${random.int(20,100)}"
复制代码 运行结果如下:
如果刷新页面,这些随机值不会发生改变,因为这些随机值是在配置文件中定义的,因此刷新页面并不会改变这些值,只有当应用重启,SpringBoot重新加载配置文件时,才会重新生成这些随机值。
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |