SpringBoot允许使用配置文件对应用程序进行配置,支持以下不同形式的配置源:

  1. 属性文件(比如application.properties)
  2. yaml文件(后缀可以是yml或者yaml)
  3. 环境变量
  4. 命令行参数

获取这些外部化属性有以下几种方式:

  1. 使用@Value注解
  2. 使用Spring的Environment抽象层进行访问
  3. 使用@ConfigurationProperties注解将一批特定属性绑定到java对象

配置源的加载顺序和优先级

由于先加载的配资源都有可能被后加载的配资源覆盖,因此认为后加载的配置源优先级更高,加载顺序如下:

  1. 默认属性(通过SpringApplication.setDefaultProperties()方法指定)
  2. 配置类(@Configuration修饰的类)上用@PropertySource注解加载的属性文件中的属性值
  3. 配置数据(如application.properties文件等)
  4. RandomValuePropertySource,只包含random.*中的属性
  5. 操作系统环境变量
  6. java系统属性(System的getProperties()方法返回的属性)
  7. 来自java:comp/env的jndi属性(只在Web服务器或应用服务器中有用)
  8. ServletContext的初始化参数(在Web.xml文件中通过<context-param.../>元素设置的初始化参数)(只在Web服务器或应用服务器中有用)
  9. ServletConfig的初始化参数(在Web.xml文件中通过<init-param.../>元素设置的初始化参数,或者通过@Servlet注解设置的初始化参数)
  10. 来自SPRING_APPLICATION_JSON的属性(嵌套在环境变量或系统属性中的JSON文本)
  11. 命令行参数
  12. 测试用例类上通过@SpringBootTest注解的properties所指定的属性(仅在单元测试生效)
  13. 测试用例类上用@TestPropertySource注解加载的属性文件中的属性值(仅在单元测试生效)
  14. 当SpringBoot的devtools工具处于激活状态时,用户Home目录中.config/spring-boot/子目录下spring-boot-devtools.properties或spring-boot-devtools.yml文件中设置的属性值(windows平台对应“C:\User\用户名”下的配置文件)

此外application.properties(包括application.yml)也有几个不同的来源,它们按如下顺序加载:

  1. jar包内的application.properties(或application.yml)
  2. jar包内的application-{profile}.properties(或application-{profile}.yml)
  3. jar包外临时指定的application.properties(或application.yml)
  4. 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文件配置的属性,可使用以下工具类

  1. YamlPropertiesFactoryBean,它将YAML文件加载为Properties对象
  2. YamlMapFactoryBean,它将YAML文件加载为Map对象
  3. 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或按如下顺序加载配置文件,后加载的文件会覆盖先加载的文件,因此,后加载的文件有更高的优先级

  1. 类加载路径的根路径
  2. 类加载路径下的/config子目录
  3. 当前路径
  4. 当前路径的/config子目录
  5. 当前路径的/config子目录的任意直接子目录,比如/config/abc、/config/aef等

如果想改变这种默认行为,可通过如下系统属性(或环境变量、或命令行参数)来设置

  1. spring.config.name:改变配置文件的文件名,默认是application。如果用OS环境变量来设置,则属性对应于SPRING_APPLICATION_NAME环境变量名。
  2. spring.config.location:改变配置文件的加载路径。如果用OS环境变量来设置,则属性对应于SPRING_APPLICATION_LOCATION环境变量名。
  3. spring.config.additional.location:添加配置文件的加载路径,不会覆盖原来的配置文件的加载路径。

不要使用SpringBoot配置属性来设置以上三种属性,因为这几个属性的加载实际非常早,只能通过系统环境变量、系统属性或命令行参数来设置。

通过spring.config.location或spring.config.additional.location指定的加载路径是有先后顺序的,比如spring.config.location设置为“optional:classpath:/fkjava/,optional:file:./fkit/”,那么加载顺序为:

  1. optional:classpath:/fkjava/
  2. optional:file:./fkit/

如果使用spring.config.additional.location来添加配置文件的加载路径,那么新增路径总是排在默认的加载路径之后。比如将spring.config.additional.location设置为“optional:classpath:/fkjava/,optional:file:./fkit/”,那么SpringBoot加载顺序为:

  1. optional:classpath:/(类加载路径的根路径)
  2. optional:classpath:/config/(类加载路径下的/config子目录)
  3. optional:file:./(当前路径)
  4. optional:file:./config/(当前路径的/config子目录)
  5. optional:file:./config/*/(当前路径的/config子目录的任意直接子目录,比如/config/abc、/config/aef等)
  6. optional:classpath:/fkjava/
  7. 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还可使用如下方式导入额外的配置文件

  1. 使用@PropertySource导入额外的属性文件
  2. 使用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: 9000
spring:
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>
<artifactId>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重新加载配置文件时,才会重新生成这些随机值。

SpringBoot--如何给项目添加配置属性及读取属性的更多相关文章

  1. 如何为你的 Vue 项目添加配置 Stylelint

    如何为你的 Vue 项目添加配置 Stylelint 现在已经是 9102 年了,网上许多教程和分享帖都已经过期,照着他们的步骤来会踩一些坑,如 stylelint-processor-html 已经 ...

  2. javascript 理解对象--- 定义多个属性和读取属性的特性

    一 定义多个属性 ECMAScript5 定义了一个Object.defineProperties()方法,用于定义多个属性.此方法接受两个对象参数: 第一个对象:要添加或修改其属性的对象 第二个对象 ...

  3. Spring配置从配置文件读取属性值

    spring将properties文件读取后在配置文件中直接将对象的配置信息填充到bean中的变量里. 原本使用PropertyPlaceholderConfigurer类进行文件信息配置.Prope ...

  4. SpringBoot 入门:项目属性配置

    开发一个SpringBoot 项目,首当其冲,必然是配置项目 一.项目属性配置 1. SpringBoot自带了Tomcat服务器,通过使用项目配置文件来修改项目的配置,如图配置了部署在80端口,目录 ...

  5. springboot项目接入配置中心,实现@ConfigurationProperties的bean属性刷新方案

    前言 配置中心,通过key=value的形式存储环境变量.配置中心的属性做了修改,项目中可以通过配置中心的依赖(sdk)立即感知到.需要做的就是如何在属性发生变化时,改变带有@Configuratio ...

  6. JAVAEE——spring01:介绍、搭建、概念、配置详解、属性注入和应用到项目

    一.spring介绍 1.三层架构中spring位置 2.spring一站式框架 正是因为spring框架性质是属于容器性质的. 容器中装什么对象就有什么功能.所以可以一站式. 不仅不排斥其他框架,还 ...

  7. 使用IDEA构建Spring-boot多模块项目配置流程

    使用IDEA构建Spring-boot多模块项目配置流程 1.创建项目 点击Create New Project 在左侧选中Spring Initializer,保持默认配置,点击下一步. 在Grou ...

  8. Spring-Boot项目中配置redis注解缓存

    Spring-Boot项目中配置redis注解缓存 在pom中添加redis缓存支持依赖 <dependency> <groupId>org.springframework.b ...

  9. Idea开发环境中,开发springboot类型的项目,如果只引入parent节点,不添加依赖节点,maven是不会加载springboot的任何依赖的

    在SpringBoot类型的项目中,我本来是要使用pringBoot,创建一个Console项目,我原本在pom.xml中添加paren节点了,天真的认为不需要再添加其他任何依赖了,可是接下来的1个小 ...

  10. SpringBoot 项目中配置多个 Jackson 的 ObjectMapper ,以及配置遇到的坑

    目录 问题说明 原因排查分析 结论总结 Jackson 自动装配分析 问题说明 我们都知道,SpringBoot 项目中,如果引入了 Jackson 的包,哪怕不配置,SpringBoot 也会帮我们 ...

随机推荐

  1. zk源码—4.会话的实现原理

    大纲 1.创建会话 (1)客户端的会话状态 (2)服务端的会话创建 (3)会话ID的初始化实现 (4)设置的会话超时时间没生效的原因 2.分桶策略和会话管理 (1)分桶策略和过期队列 (2)会话激活 ...

  2. Java连接Redis常用操作

    1.去重 package Data; import redis.clients.jedis.Jedis; public class TestRedisUniq { public static Jedi ...

  3. python开发箱号批量查询关联SN号码的程序

    # 需要导入的包 import tkinter as tk from tkinter import ttk, messagebox, filedialog import pyodbc import p ...

  4. 大模型流式调用规范(SSE)

    随着大语言模型的广泛应用,如何高效地与其进行接口调用成为一个关键问题.传统的请求-响应模式在面对大模型生成大量文本时存在响应延迟高.用户体验差等问题.流式输出(Streaming)是解决该问题的重要手 ...

  5. python-docx 设置表格边框

    # -*- coding: utf-8 -*- """ Created on Sat Oct 24 17:21:31 2020 pip install -i https: ...

  6. Dify 框架连接 PGSQL 数据库与 Sandbox 环境下的 Linux 系统调用权限问题

    Dify 框架连接 PGSQL 数据库与 Sandbox 环境下的 Linux 系统调用权限问题 背景 在使用 Dify 框架进行开发时,遇到了两个主要的技术挑战: 代码节点连接到 PGSQL(Pos ...

  7. <HarmonyOS第一课08>保存应用数据

    视频链接: https://developer.huawei.com/consumer/cn/training/course/slightMooc/C101717498132814493 ?ha_so ...

  8. servlet @WebServlet注解

    web开发中可以通过web.xml写servlet标签表明一个类是Servlet,servlet3.0后可以使用@WebServlet表示一个类为Servlet. @WebServlet 参数 说明 ...

  9. 『Plotly实战指南』--在金融数据可视化中的应用(下)

    在金融市场的复杂博弈中,可视化技术如同精密的导航仪. 传统静态图表正在被交互式可视化取代--据Gartner研究,采用动态可视化的投资机构决策效率提升达47%. 本文的目标是探讨如何利用 Plotly ...

  10. 获取传入值的上一个月【月初】和【月末】【yyyy-MM-dd】

    获取传入值的上一个月[月初]和[月末] 常量值:String DATE_FORMAT_YYYY_MM_DD = "yyyy-MM-dd"; // 获取传入值的上一个月月初 : fo ...