找回密码
 立即注册
首页 业界区 业界 SpringBoot--如何给项目添加配置属性及读取属性 ...

SpringBoot--如何给项目添加配置属性及读取属性

准挝 昨天 15:36
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位(上一小节)。
  1. @SpringBootApplication
  2. public class App
  3. {
  4.    public static void main(String[] args)
  5.    {
  6.       // 设置spring.application.json系统属性
  7.       // 属性值为{“fkjava”:{name:""SPringBoot服务器", age:20, servers:["fkjava.org", "crazyit.org"]}}
  8.       System.setProperty("spring.application.json",
  9.             "{"fkjava":{"name":"SPringBoot服务器", "age":20, " +
  10.             ""servers":["fkjava.org", "crazyit.org"]}}");
  11.       SpringApplication.run(App.class, args);
  12.    }
  13. }
复制代码
application.properties文件内容:
  1. fkjava.name=springboot软件服务器
  2. fkjava.age=35
复制代码
  1. @RestController
  2. public class HelloController {
  3.     // 使用@Value注解访问配置属性
  4.     @Value("${fkjava.name}")
  5.     private String name;
  6.     @Value("${fkjava.age}")
  7.     private String age;
  8.     @Value("${fkjava.servers[0]}")
  9.     private String server1;
  10.     @Value("${fkjava.servers[1]}")
  11.     private String server2;
  12.     @GetMapping
  13.     public Map<String, String> hello()
  14.     {
  15.         return Map.of("名称", name, "年龄", age,
  16.                 "服务器1", server1, "服务器2", server2);
  17.     }
  18. }
复制代码
输出结果:
1.png

可见,通过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对应于
  1. spring:
  2.   application:
  3.     name: "cruncher"
复制代码
如果YAML配置的属性包含多个列表项,那么它会被转化成【index】形式,比如
  1. fkjava:
  2.   name: "SpringBoot软件"
  3.   age: 20
  4.   servers:
  5.     - www.fkjava.org
  6.     - 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(系统会自动加载)
  1. fkjava:
  2.   server:
  3.     name: "疯狂软件服务器"
  4.     port: 9000
复制代码
文件路径:/resources/fk/fk.yml(系统不会自动加载)
  1. fkjava:
  2.   name: "疯狂软件"
  3.   age: 20
  4.   servers:
  5.     - www.fkjava.org
  6.     - www.crazyit.org
复制代码
  1. //定义一个配置环境后处理器来加载fk.yml
  2. public class FkEnvironmentPostProcessor implements EnvironmentPostProcessor
  3. {
  4.    // 创建YamlPropertySourceLoader,用于加载YAML文件
  5.    private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
  6.    @Override
  7.    public void postProcessEnvironment(ConfigurableEnvironment environment,
  8.          SpringApplication application)
  9.    {
  10.       // 指定自定义的配置文件
  11.       Resource path = new ClassPathResource("fk/fk.yml");
  12.       // 加载自定义配置文件
  13.       PropertySource<?> ps = null;
  14.       try
  15.       {
  16.          ps = this.loader.load("custom-resource", path).get(0);
  17.       }
  18.       catch (IOException e)
  19.       {
  20.          e.printStackTrace();
  21.       }
  22.       System.out.println("fkjava.name: " + ps.getProperty("fkjava.name"));
  23.       System.out.println("fkjava.age: " +ps.getProperty("fkjava.age"));
  24.       System.out.println("fkjava.servers[0]: " +ps.getProperty("fkjava.servers[0]"));
  25.       System.out.println("fkjava.servers[1]: " +ps.getProperty("fkjava.servers[1]"));
  26.       // 将PropertySource中的属性添加到Environment配置环境中
  27.       environment.getPropertySources().addLast(ps);
  28.    }
  29. }
复制代码
可通过/META-INF/spring.factories来注册配置环境后处理器:
  1. org.springframework.boot.env.EnvironmentPostProcessor=org.crazyit.app.FkEnvironmentPostProcessor
复制代码
这样一来application.yml和fk.yml都被加载进来,下来可以在其他任何Bean中通过@Value来访问它们
  1. @RestController
  2. public class HelloController
  3. {
  4.    // 使用@Value注解访问配置属性
  5.    @Value("${fkjava.server.name}")
  6.    private String serverName;
  7.    @Value("${fkjava.server.port}")
  8.    private String serverPort;
  9.    @Value("${fkjava.age}")
  10.    private String age;
  11.    @GetMapping
  12.    public String hello()
  13.    {
  14.       return "名称: " + serverName + ", 端口: " + serverPort
  15.             + ", 年龄: " + age;
  16.    }
  17. }
复制代码
如果仅需要加载自定义的Yaml文件,在组件中使用这些配置属性,并不需要将属性添加到配置环境中,那么只要在容器中配置一个YamlPropertiesFactoryBean工厂Bean或YamlMapFactoryBean工厂Bean,它们就会自动读取Yaml文件,将其中的配置内容加载为Properties对象或Map对象。
  1. @Configuration
  2. public class MyConfig
  3. {
  4.    // 在容器中配置一个YamlPropertiesFactoryBean
  5.    @Bean
  6.    public YamlPropertiesFactoryBean fkProps()
  7.    {
  8.       var factory = new YamlPropertiesFactoryBean();
  9.       factory.setResources(new ClassPathResource("fk/fk.yml"));
  10.       return factory;
  11.    }
  12. }
复制代码
spring中的工厂Bean有一个特征:当程序通过spring容器获取工厂Bean时,实际获取到的是该工厂的产品(getObject()方法的返回值),因此当程序获取上面配置的fkProps时,实际返回的是一个Properties对象。
  1. @RestController
  2. public class HelloController
  3. {
  4.    // 使用@Value注解访问配置属性
  5.    @Value("${fkjava.server.name}")
  6.    private String serverName;
  7.    @Value("${fkjava.server.port}")
  8.    private String serverPort;
  9.    // 指定将容器中fkProps Bean注入fkProps实例变量
  10.    @Resource(name = "fkProps")
  11.    private Properties fkProps;
  12.    @GetMapping
  13.    public String hello()
  14.    {
  15.       return "名称: " + serverName + ", 端口: " + serverPort
  16.             + ", 年龄: " + fkProps.getProperty("fkjava.age");
  17.    }
  18. }
复制代码
改变配置文件的位置

默认情况下,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前缀的路径不能使用通配符
每个加载路径只能在最后面使用一个通配符
  1. @SpringBootApplication
  2. public class App
  3. {
  4.         static {
  5.                 // 设置配置文件的文件名
  6.                 // 通过系统属性设置SpringBoot配置文件的主文件名可以是application和fk
  7.                 // 这样SpringBoot就会自动加载application.yml和fk.yml两个配置文件
  8.                 System.setProperty("spring.config.name", "application, fk");
  9.                 // 设置配置文件的加载路径
  10.                 // optional:表示如果classpath下没有指定的配置文件,则不报错,如果不加这个前缀,若该路径下不存在配置文件,就会抛出异常
  11.                 System.setProperty("spring.config.location",
  12.                                 "classpath:/, optional:classpath:/fk/");
  13.                 // 设置额外的加载路径
  14. //                System.setProperty("spring.config.additional-location",
  15. //                                "optional:classpath:/fk/");
  16.         }
  17.         public static void main(String[] args)
  18.         {
  19.                 // 创建Spring容器、运行Spring Boot应用
  20.                 SpringApplication.run(App.class, args);
  21.         }
  22. }
复制代码
导入额外的配置文件

在spring容器刷新之后,SpringBoot还可使用如下方式导入额外的配置文件

  • 使用@PropertySource导入额外的属性文件
  • 使用spring.config.import导入额外的配置文件(包括属性文件和Yaml文件)
如果只是为应用中的Bean组件导入一些配置属性,完全可通过上面两种方式来导入。以下示例:
resources\fk\fk.yml文件内容:(只能通过spring.config.import导入)
  1. fkjava:
  2.   name: "疯狂软件"
  3.   age: 25
  4.   servers:
  5.     - www.fkjava.org
  6.     - www.crazyit.org
复制代码
resources\fk\crazyit.properties文件内容:(spring.config.import和@PropertySource都能导入)
  1. crazyit.book.name=Spring Boot
  2. crazyit.book.price=128
复制代码
resources\applocation.yml文件内容:
  1. fkjava:
  2.   server:
  3.     name: "疯狂软件服务器"
  4.     port: 9000spring:  config:    # 指定导入类加载路径下fk/fk.yml文件    import: optional:classpath:/fk/fk.yml
复制代码
通过@PropertySource导入crazyit.properties文件示例:
  1. @SpringBootApplication
  2. // 导入类加载路径下fk/crazyit.properties文件
  3. @PropertySource("classpath:/fk/crazyit.properties")
  4. public class App
  5. {
  6.    public static void main(String[] args)
  7.    {
  8.       // 创建Spring容器、运行Spring Boot应用
  9.       SpringApplication.run(App.class, args);
  10.    }
  11. }
复制代码
使用占位符

配置文件中可使用占位符(${})来引用已定义的属性,或者引用其他配置源(系统属性、环境变量、命令参数等)配置的属性。示例如下:
resources\applocation.yml文件内容:
  1. app:
  2.   name: "占位符"
  3.   # 引用配置文件中的配置属性
  4.   description: "${app.name}应用演示了如何在配置文件中使用占位符"
  5. book:
  6.   # 引用外部的配置属性
  7.   description: ${book.name}是一本非常优秀的图书
  8. server:
  9.   # 配置服务端口
  10.   port: ${port}
复制代码
添加命令行参数:--book.name="哈利波特" --port=9090,然后启动应用就会生效。
读取构建文件的属性

SpringBoot允许配置文件读取构建文件(pom.xml或build.gradle)的属性.
只要在pom.xml文件中定义如下元素,就能在配置文件中通过“@属性名@”来引用pom.xml文件中的属性
  1. <parent>
  2.    <groupId>org.springframework.boot</groupId>
  3.    spring-boot-starter-parent</artifactId>
  4.    <version>2.4.2</version>
  5. </parent>
复制代码
resources\applocation.yml文件内容:
  1. app:
  2.   java:
  3.     # 引用pom.xml文件中的属性
  4.     version: @java.version@
  5.   sourceEncoding: @project.build.sourceEncoding@
  6.   name: @name@
  7.   version: @version@
复制代码
对于Gradle项目,首先要在build.gradle中对java插件的processResources进行如下配置,然后将这段配置加到build.gradle文件的最后。
  1. // 配置Java插件的processResources Task
  2. processResources {
  3.     expand(project.properties)
  4. }
复制代码
接下来即可在配置文件中通过“${属性名}”(这里不再是占位符的表示)的形式引用build.gradle中属性。
resources\applocation.yml文件内容:
  1. app:
  2.   java:
  3.     version: "${sourceCompatibility}"
  4.   name: "${rootProject.name}"
  5.   version: "${version}"
复制代码
配置随机值

如果需要为应用配置各种随机值(如随机整数、uuid等),可通过在配置文件中使用${random.xxx}的形式来生成随机值。示例如下:
resources\applocation.yml文件内容:
  1. fkjava:
  2.   secret: "${random.value}"
  3.   number: "${random.int}"
  4.   bignumber: "${random.long}"
  5.   uuid: "${random.uuid}"
  6.   number-less-than-ten: "${random.int(10)}"
  7.   number-in-range: "${random.int(20,100)}"
复制代码
运行结果如下:
2.png

如果刷新页面,这些随机值不会发生改变,因为这些随机值是在配置文件中定义的,因此刷新页面并不会改变这些值,只有当应用重启,SpringBoot重新加载配置文件时,才会重新生成这些随机值。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册