Spring Boot
- 全局配置文件
- application.properties
- application.yml
- 全局配置文件的优先级
- 从全局配置文件中获取数据的注解
- 从外部属性文件中获取数据的注解
- 全局配置文件的配置项
- 通用配置项
- 数据源配置项
- JPA 配置项
- 日志配置项
- 配置文件特定配置项
- Profile 特定配置项
- 配置类
- 配置文件中使用引用变量 ${} 和随机值
- 配置文件中使用 profile
- 多个配置文件的优先级
全局配置文件
在 Spring Boot 中,全局配置文件存在两种形式,分别为 application.properties 或 application.yml 文件(其全局配置文件名必须为 application ,不可修改)。这两种配置文件配置方式存在差异,但都是用于定义 Spring Boot 应用的全局配置(如指定数据库连接信息、配置服务器端口、设置日志级别等),其作用都是修改 Spring Boot 的自动配置默认值,以满足特定的应用需求。
这两种配置文件通常存放在项目的 src/main/resources 目录下。Spring Boot 在启动时会自动加载这个文件,并根据其中的配置项进行应用的初始化。
注:
application.properties 与 application.yml 都可以完成相同的配置任务,但在实际开发中,通常会根据项目的复杂性和开发者的偏好来选择使用全局配置文件的形式。application.properties 作为 Spring Initializr 默认自动生成的配置文件,在实际应用中具有广泛的应用。而对于复杂的配置需求,使用 application.yml 可能会更加方便和清晰。同时,Spring Boot 也支持从外部资源加载配置文件(如从环境变量、命令行参数或远程配置中心获取配置信息),使得应用的配置更加灵活和可维护。
application.properties
application.properties 是传统的键值对形式的配置文件,每个配置项占据一行,键和值之间使用等号连接。这种形式的配置文件简单直观,非常合适简单的配置需求。
简单示例:
# 服务器端口
server.port=8080
# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/mydatabase
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 日志级别
logging.level.root=INFO
# 自定义属性(自定义了一个名为 my.custom.property 的属性,并将其值设置为 custom_value )
my.custom.property=custom_value
application.yml
application.yml 是数据序列化形式的配置文件,基于 YAML( YAML Ain’t Markup Language )语法来定义配置项,能够清晰地表示数据的层次结构。
数据的层级关系以缩进的形式来表示。通常,每个层级使用两个空格进行缩进。缩进的空格数不是固定的,但相同层级的元素必须左对齐。数据是以键值对形式,键和值之间用冒号分隔,并且冒号后面必须有一个空格。同时区分大小写,默认采用 UTF-8 编码。
YAML 支持多种数据类型:
- 字符串:可以不加引号,若字符串中包含特殊字符或需要转义,可以使用双引号或单引号。
双引号中的特殊字符会被转义,而单引号中的特殊字符则保持原样
- 数字:可以直接书写,不需要引号
- 布尔值:通常以小写形式书写,如 true 或 false
- 列表(数组):以连字符
-
开头,每个列表项独占一行,并缩进到相同的层级- 映射(字典/哈希表):由键值对组成,键值对之间通过换行分隔,并缩进到相同的层级
简单示例:
# 服务器端口
server:
port: 8080
# 数据库配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydatabase
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
# 日志级别
logging:
level:
root: INFO
# 自定义属性(自定义了一个名为 my.custom.property 的属性,并将其值设置为 custom_value )
my:
custom:
property: custom_value
全局配置文件的优先级
application.properties 的优先级高于 application.yml 。这意味着当两个文件中存在相同的配置项时,application.properties 中的配置会覆盖 application.yml 中的相应配置。
从全局配置文件中获取数据的注解
在 Spring Boot 中,@Value 与 @ConfigurationProperties 两个注解都有用于从全局配置文件中获取数据的功能,但其存在一定的区别。一般情况,当只需全局配置文件中某一个值时,使用 @Value 注解;当 JavaBean 与全局配置文件的属性值对应时,使用 @ConfigurationProperties 注解。
区别以下:
-
注入方式:
@Value 注解用于单个属性值的注入。通常与 ${} 配合使用,用于读取全局配置文件中的具体属性值,并将其注入到字段、方法参数或构造函数参数中
@ConfigurationProperties 注解用于将一组相关的配置属性绑定在一个 POJO 上,允许定义一个 Java 类,其字段与全局配置文件中的属性一 一对应,Spring Boot 会自动将全局配置文件中的属性映射到类的字段上 -
灵活性:
@Value 注解相对简单直接,适用于单个属性的注入。若需要注入多个相关属性,可能需要为每个属性都写一个 @Value 注解,这会导致代码较为冗余
@ConfigurationProperties 注解在处理多个相关属性时,可以定义一个类来封装这些属性,使得代码更加整洁和易于管理 -
类型安全:
@Value 注解需要确保注入的值与字段的类型匹配,否则可能会导致类型转换异常
@ConfigurationProperties 注解在绑定属性时会自动进行类型转换,提高了类型安全性 -
配置文件的更新:
当全局配置文件中的属性值发生变化时,@Value 注解的字段不会自动更新,除非重新启动应用程序
而使用 @ConfigurationProperties 注解的类,Spring Boot 会提供一个重新加载配置的功能,使得当配置文件更新时,类的字段也会自动更新 -
优先级:
在同一个类中,若同时使用 @Value 和 @ConfigurationProperties 注解来注入同一个属性时,@ConfigurationProperties 注解的优先级会更高,会覆盖 @Value 注解的值 -
编程校验规范:
@Value 注解支持 Spring 表达式写法( SpEL ),但不支持 JSR303 数据校验功能
@ConfigurationProperties 注解不支持 Spring 表达式写法( SpEL ),但支持 JSR303 数据校验功能 -
复杂数据绑定:
@Value 注解不支持复杂数据绑定, @ConfigurationProperties 注解支持复杂数据绑定,如 Map 、List 等
简单示例:
1.使用 @Value 注解从全局配置文件( application.properties )中获取数据
首先,在 SpringBootDemo 项目的 Entity 包中创建 Admin 类
package cn.edu.SpringBootDemo.Entity;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component // 标记为组件,放到 Spring IoC 容器中
public class Admin {
@Value("#{2024+3+18}") // #{ spring 表达式}
private int id;
@Value("${admin.username}") // 通过 ${} 获取全局配置文件的数据
private String username;
@Value("${admin.password}")
private String password;
@Value("true") // 直接注入数据值
private boolean result;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public boolean isResult() {
return result;
}
public void setResult(boolean result) {
this.result = result;
}
@Override
public String toString() {
return "Admin{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", result=" + result +
'}';
}
}
然后,在 application.properties 全局配置文件中配置 Admin 对象所需要的具体属性值
admin.username=曹操
admin.password=cc
最后,在测试类 SpringBootDemoApplicationTests 进行测试
package cn.edu.SpringBootDemo;
import cn.edu.SpringBootDemo.Entity.Admin;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringBootDemoApplicationTests {
@Autowired
private Admin admin;
@Test
void contextLoads() {
System.out.println(admin);
}
}
结果如图:
2. 使用 @ConfigurationProperties 注解从全局配置文件( application.yml )中获取数据
首先,在 Entity 包中创建 User 类和 PhoneNumber 类
// User 类
package cn.edu.SpringBootDemo.Entity;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Component // 标记为组件,放到 Spring IoC 容器中
@ConfigurationProperties( prefix = "user" ) // 绑定配置文件,从配置文件中注入数据
public class User {
private int id;
private String username;
private String password;
private Date birthday;
private boolean result;
private List<String> list;
private Map<String,Object> map;
private PhoneNumber phoneNumber;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public boolean isResult() {
return result;
}
public void setResult(boolean result) {
this.result = result;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public Map<String, Object> getMap() {
return map;
}
public void setMap(Map<String, Object> map) {
this.map = map;
}
public PhoneNumber getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(PhoneNumber phoneNumber) {
this.phoneNumber = phoneNumber;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", birthday=" + birthday +
", result=" + result +
", list=" + list +
", map=" + map +
", phoneNumber=" + phoneNumber +
'}';
}
}
// PhoneNumber 类
package cn.edu.SpringBootDemo.Entity;
import org.springframework.stereotype.Component;
@Component
public class PhoneNumber {
private int id;
private int phone;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getPhone() {
return phone;
}
public void setPhone(int phone) {
this.phone = phone;
}
@Override
public String toString() {
return "PhoneNumber{" +
"id=" + id +
", phone=" + phone +
'}';
}
}
然后,在 application.yml 全局配置文件中配置 User 对象具体的属性值
user:
id: 2024318
username: 曹操
password: cc
birthday: 2024/3/18
result: true
list:
-a
-b
-c
map: {a:1,b:2}
phone-number: {id: 2024318,phone: 8397065}
# 对象或 Map 集合都可以使用 {} 表示
# 列表(数组)表示方式还可以使用 [] 表示。如 list: [a,b,c]
最后,在测试类 SpringBootDemoApplicationTests 进行测试
package cn.edu.SpringBootDemo;
import cn.edu.SpringBootDemo.Entity.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SpringBootDemoApplicationTests {
@Autowired
private User user;
@Test
void contextLoads() {
System.out.println(user);
}
}
结果如图:
从外部属性文件中获取数据的注解
在上面的 @Value 和 @ConfigurationProperties 两个注解中,只能从全局配置文件( application.properties 或 application.yml ) 中获取数据。通常并不是所有的数据都在全局配置文件中,当需要获取外部属性文件的数据时,可以使用 @PropertySource 注解。
简单示例:
在 @Value 注解示例的基础上
首先,在 Admin 类上添加 @PropertySource 注解,使用方式为 @PropertySource({“classpath:外部属性文件”})
然后,在 resources 目录下创建 admin.properties 外部属性文件,将 application.properties 全局配置文件中的属性值剪切到 admin.properties 外部属性文件中
admin.username=曹操
admin.password=cc
最后,同样在测试类 SpringBootDemoApplicationTests 进行测试
结果如图:
若没有 @PropertySource 注解,使用 @Value 注解或 @ConfigurationProperties 注解是无法获取外部属性文件的数据
测试中报错如图:
全局配置文件的配置项
Spring Boot 参考文档的全局配置文件配置项说明
在 Spring Boot 中,全局配置文件用于定义应用程序的各种配置项。这些配置项可以覆盖 Spring Boot 的默认设置,也可以用于自定义应用程序的行为。
常见的 Spring Boot 全局配置文件中的配置项:
通用配置项
- server.port:设置应用程序的 HTTP 端口号
- server.servlet.context-path:设置应用程序的上下文路径
- spring.application.name:设置应用程序的名称
数据源配置项
- spring.datasource.url:设置数据库连接 URL
- spring.datasource.username:设置数据库连接用户名
- spring.datasource.password:设置数据库连接密码
- spring.datasource.driver-class-name:设置数据库驱动类名
JPA 配置项
- spring.jpa.hibernate.ddl-auto:设置 Hibernate 的 DDL(数据定义语言)自动更新策略
- spring.jpa.show-sql:是否在控制台显示 SQL 语句
日志配置项
- logging.level.root:设置日志的根级别
- logging.file:设置日志文件的输出位置
配置文件特定配置项
- 自定义属性:可以定义任何自定义属性,并在应用程序中通过 @Value 注解或 Environment 类来访问
Profile 特定配置项
- 特定 Profile 的配置:可以在 application-{profile}.properties 或 application-{profile}.yml 中为特定 Profile 定义配置
注:
Spring Boot 默认的配置类内的配置项生效是有条件的,需要通过一系列的 @ConditionalXXX 注解来判断,当这些条件都为 true 时,配置项才生效。
配置类
在 Spring Boot 中,当自动配置不能满足需求时,可以通过配置类对自定义 bean 进行 bean 容器的装配工作。另外,使用 Spring Boot 配置类的方法通常比使用 @ImportResource 注解来引入 XML 配置文件的方法更高效。因此只简单介绍配置类的方法。
简单示例:
在 Admin 类示例的基础上
首先,在项目中创建 Configuration 包,并且在包内创建一个 MyConfiguration 类
package cn.edu.SpringBootDemo.Configuration;
import cn.edu.SpringBootDemo.Entity.Admin;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration // 声明为配置类
public class MyConfiguration {
@Bean // 该方法返回值为注入 Spring IoC 容器的对象
public Admin admin(){ // admin()--方法名默认为 Spring 容器的 id 名称
return new Admin();
}
}
然后,在全局配置文件 application.properties 中添加配置
spring.main.allow-bean-definition-overriding=true
注:
在没有对全局配置文件配置这个时,运行出现报错,提示 bean 重复,需要配置 spring.main .allow-bean-definition-overriding=true
报错如图:
最后,同样在测试类 SpringBootDemoApplicationTests 进行测试
结果如图:
配置文件中使用引用变量 ${} 和随机值
在 Spring Boot 的配置文件中,可以使用引用变量 ${} 和随机值来增强配置的灵活性和动态性。通过 Spring Boot 的引用变量来允许在配置文件中引用之前定义的值或生成随机值。
简单示例:
1.使用引用变量 ${}
使用引用变量 ${} 在配置文件中引用之前定义的值。这允许在不同的配置位置之间共享值,从而避免重复和硬编码。
若在 application.properties 全局配置文件中定义了以下属性
admin.username=曹操
admin.password=cc
则可以在同一个配置文件或其他配置文件中引用这些属性
admin.object=${admin.username} ${admin.password}
在运行时,Spring Boot 会解析 ${admin.username} 和 ${admin.password} 对应的值,从而生成完整的 admin.object 属性。
2.使用随机值
Spring Boot 还提供了生成随机值的功能,这对于需要随机密码、端口号等场景非常有用。可以使用 random. 前缀来生成随机值。
可以配置生成一个随机的整数作为服务器端口
server.port=${random.int}
或者,可以指定随机数的范围:这将会生成一个在1000到9999之间的随机整数。
my.random.number=${random.int(1000,9999)}
此外,还可以生成随机字符串:这将会生成一个随机的 UUID
my.random.uuid=${random.uuid}
注:
- 引用变量和随机值功能主要在 application.properties 或 application.yml 全局配置文件中使用
- 当使用 YAML 格式的全局配置文件( application.yml )时,引用变量的语法稍有不同
- 随机值生成器是每次应用上下文启动时运行一次,因此若在运行时多次请求同一个随机属性,其将返回相同的值。若需要每次请求都返回不同的随机值,可能需要在代码中实现这一逻辑
- 确保引用的属性在引用之前已经被定义,否则 Spring Boot 将无法解析,可能会抛出异常
配置文件中使用 profile
在 Spring Boot 中,配置文件使用 Profile 是一种灵活的方式来区分不同的环境,如开发环境、测试环境和生产环境,并为每个环境提供不同的配置。通过使用 Profile ,可以确保应用程序在不同环境中使用正确的配置,从而提高应用的灵活性和可维护性。
使用 Profile 的关键步骤:
-
创建 Profile 特定的配置文件:在项目的 resources 目录下,可以创建针对每个 Profile 的配置文件。这些文件通常命名为 application-{profile}.properties 或 application-{profile}.yml ,其中 {profile} 是 Profile 的名称
-
配置 Profile 特定的属性:在每个 Profile 特定的配置文件中,可以定义该 Profile 特有的属性。这些属性将只在该 Profile 激活时生效
-
激活 Profile 的方法:
- 在配置文件中设置:在 application.properties 或 application.yml 中,通过 spring.profiles.active 属性来指定激活的 Profile
- 通过命令行参数:在启动 Spring Boot 应用时,使用 –spring.profiles.active={profile} 参数来指定激活的 Profile
- 在环境变量中设置:可以通过设置环境变量来激活 Profile
-
使用 @Profile 注解:在 Spring 组件(如 @Component 、@Configuration 或 @ConfigurationProperties )上,可以使用 @Profile 注解来指定这些组件在哪些 Profile 下生效
-
Profile 分组和优先级:Spring Boot 还支持 Profile 分组,允许定义 Profile 的继承关系和组合。此外,当多个 Profile 被激活时,优先级也是需要考虑的
简单示例:
首先,有两个Profile:a 和 b 。可以创建两个配置文件:application-a.properties 和 application-b.properties,并为每个环境配置不同的服务器端口
然后,在不做任何配置情况下,只有默认的全局配置文件服务器端口会生效
最后,通过设置 spring.profiles.active 属性或在命令行中使用 --spring.profiles.active 参数,实现切换不同的环境配置
多个配置文件的优先级
在 Spring Boot 中,多个配置文件的优先级是由多种因素决定的。
-
命令行参数:通过命令行参数传递的配置具有最高的优先级。这意味着在启动 Spring Boot 应用时,通过
--
前缀指定的配置项将覆盖其他所有配置源中的相同配置项 -
Java 系统属性:通过 Java 系统属性(如 -Dkey=value )配置的值也具有较高的优先级,但通常低于命令行参数
-
外部配置文件:Spring Boot 会从项目的外部位置加载配置文件,这些位置包括 jar 包外部的指定目录以及类路径( classpath )外部的位置。外部配置文件通常具有较高的优先级,因为其可以方便地覆盖打包在 jar 包内部的配置
- jar 包外部指定的配置文件:如 application-prod.properties 或 application-prod.yml ,这些文件通常针对特定的 Profile ,并具有较高的优先级
- jar 包外部的普通配置文件:如 application.properties 或 application.yml ,这些文件没有针对特定的 Profile ,但优先级仍然较高
-
内部配置文件:位于 jar 包内部或类路径( classpath )下的配置文件具有较低的优先级。这些文件通常是在构建 jar 包时就已经确定的,因此不容易被外部配置覆盖
- 内部指定配置文件:针对特定 Profile 的内部配置文件,如位于 src/main/resources/config/application-prod.properties
- 内部普通配置文件:如 src/main/resources/application.properties 或 src/main/resources/application.yml
-
Profile 特定的配置文件:当使用 Spring Boot 的 Profile 功能时,针对特定 Profile 的配置文件(如 application-a.properties 、 application-b.properties 等)会根据激活的 Profile 具有相应的优先级。激活的 Profile 的配置会覆盖默认的配置
-
默认配置:若没有其他配置源提供某个配置项的值,Spring Boot 会使用其内置的默认配置
总的来说,配置文件的优先级是从外部到内部、从特定到通用的顺序。命令行参数和外部配置文件具有最高的优先级,而内部配置文件和默认配置具有较低的优先级。同时,使用 Profile 时,特定 Profile 的配置会覆盖默认配置。这种优先级机制使得 Spring Boot 能够灵活地处理多配置文件,并满足各种复杂环境的配置需求。