SpringBoot3 基础教程之五基础特性
大纲
- SpringBoot3 基础教程之一快速入门
- SpringBoot3 基础教程之二常规配置
- SpringBoot3 基础教程之三 Web 开发
- SpringBoot3 基础教程之四 Web 开发
- SpringBoot3 基础教程之五基础特性
- SpringBoot3 基础教程之六场景整合
- SpringBoot3 基础教程之七场景整合
- SpringBoot3 基础教程之八场景整合
- SpringBoot3 基础教程之九核心原理
前言
本章节所需的案例代码,可以直接从 GitHub 下载对应章节 spring-boot3-06,除特别说明外。
SpringApplication
自定义 banner
推荐使用 Spring Boot Banner 在线生成工具,制作并下载英文 banner.txt 文件,然后将它放到项目的 /src/main/resources 目录下,这样就可以实现应用的个性化启动。
自定义 SpringApplication
1 | import org.springframework.boot.Banner; |
上面的代码等同于以下配置内容,值得一提的是,配置文件的优先级更高
1 | # 关闭Banner |
FluentBuilder API
SpringBoot 支持以 Builder 方式构建 SpringApplication,通过 FluentBuilder API 设置应用属性。
1 | import org.springframework.boot.Banner; |
Profiles 环境隔离
简单介绍
Profiles 提供环境隔离能力,支持快速切换开发、测试、生产环境,使用步骤如下:
- 1、
指定环境:指定哪些组件、配置在哪个环境生效 - 2、
激活环境:这个环境对应的所有组件和配置就应该生效
基础使用
指定环境
- Spring Profiles 提供一种隔离配置的方式,使其仅在特定环境生效
- 任何
@Component、@Configuration或@ConfigurationProperties都可以使用@Profile注解,来指定自身何时被加载。值得一提的是,Spring 容器中的组件都可以被@Profile注解标记。
1 |
|
1 |
|
环境激活
在 application.properties 配置文件中,指定需要激活的环境
1 | =dev |
或者同时激活多个环境
1 | =dev,test |
提示
- 也可以使用命令行激活环境,如
java -jar xxxx.jar --spring.profiles.active=dev,test - 还可以配置默认环境,即不标注
@Profile注解的组件永远都会生效 - 以前默认环境叫
default - 自定义默认环境
spring.profiles.default=test, - 不推荐使用自定义默认环境的方式,而是推荐使用激活方式激活指定环境
环境包含
包含指定的环境,即不管激活哪个环境,包含指定的环境都会生效
1 | =dev |
最佳实践
- 生效的环境 = 激活的环境 / 默认环境 + 包含的环境
- 企业项目里面的使用规则
- 基础的配置内容,如 MyBatis、Log 写到包含环境中
- 需要动态切换变化的配置内容,如 DataBase、Redis 写到激活的环境中
Profiles 分组
创建 prod 分组,指定包含的 db 和 mq 配置。当使用命令行激活 java -jar xxx.jar --spring.profiles.active=prod ,就会激活 prod 分组,包括激活 db,mq 的配置文件。
1 | =db,mq |
或者使用数组的写法
1 | =db |
Profiles 配置文件
application-{profile}.properties可以作为指定环境的配置文件- 激活这个环境,对应的配置文件就会生效,最终生效的所有配置如下
application.properties主配置文件,任意时候都会生效application-{profile}.properties指定环境配置文件,激活指定环境时会生效- 如果发生了配置冲突,默认以激活的环境配置文件为准,即
application-{profile}.properties的优先级高于application.properties
特别注意
spring.profiles.default、spring.profiles.active、spring.profiles.include 的配置信息只能写在 application.properties 中,如果写在 application-{profile}.properties 是无效的。
外部化配置
线上应用如何快速修改配置,并应用最新配置?
- SpringBoot 使用
配置优先级+外部配置,可以简化配置更新、简化运维。 - 只需要往 Jar 应用所在的文件夹放一个
application.properties最新配置文件,重启项目后就能自动应用最新的配置信息,无需重新编译打包代码。
配置优先级
SpringBoot 允许将配置外部化,以便可以在不同的环境中使用相同的应用程序代码。支持使用各种外部配置源,包括 Properties 文件、YAML 文件、环境变量和命令行参数。使用 @Value 注解可以获取到配置参数的值,也可以用 @ConfigurationProperties 注解将所有属性绑定到 POJO 中。
- 以下是 SpringBoot 属性源的加载顺序,后面的会覆盖前面的值。由低到高,高优先级配置会覆盖低优先级配置。
- 默认属性(通过
SpringApplication.setDefaultProperties()指定的) @PropertySource加载指定的配置(需要写在@Configuration类上才可生效)- 配置文件(
application.properties/yml等) RandomValuePropertySource支持的random.*配置(如@Value("${random.int}"))- 系统环境变量
- Java 系统属性(
System.getProperties()) - JNDI 属性(来自
java:comp/env) - ServletContext 初始化参数
- ServletConfig 初始化参数
- SPRING_APPLICATION_JSON 属性(内置在环境变量或系统属性中的 JSON)
- 命令行参数
- 测试属性 (
@SpringBootTest进行测试时指定的属性) - 测试类
@TestPropertySource注解 - Devtools 设置的全局属性(
$HOME/.config/spring-boot)
- 默认属性(通过
总结
配置信息可以写在很多位置,常见的优先级顺序: 命令行 > 配置文件 > SpringApplication 配置。
- 配置文件的优先级如下(越往后优先级越高)
- Jar 包内的
application.properties/yml - Jar 包内的
application-{profile}.properties/yml - Jar 包外的
application.properties/yml - Jar 包外的
application-{profile}.properties/yml
- Jar 包内的
提示
- 优先级顺序:
包外>包内; 同级情况:Profiles 配置>Application 配置 - 建议使用同一种格式的配置文件。如果
xxx.properties和xxx.yml同时存在,则xxx.properties的优先级更高 - 所有参数均可由命令行传入,使用
--参数项=参数值格式,参数将会被添加到环境变量中,且优先级大于配置文件。比如java -jar app.jar --name="Spring",可以使用@Value("${name}")获取参数值。
- 实际应用场景
- 包内:
application.propertiesserver.port=8000 - 包内:
application-dev.propertiesserver.port=9000 - 包外:
application.propertiesserver.port=8001 - 包外:
application-dev.propertiesserver.port=9001 - 应用启动后的端口: 命令行 > 9001 > 8001 > 9000 > 8000
- 包内:
外部配置说明
SpringBoot 应用在启动的时候,会自动寻找 application.properties 和 application.yaml 配置文件,然后进行加载。配置文件的加载顺序如下(越往后优先级越高):
类路径(内部)
- 类根路径(
classpath) - 类根路径(
classpath)下的/config子目录
- 类根路径(
当前路径(Jar 应用所在的位置)
- 当前路径
- 当前路径下的
/config子目录 /config目录的直接子目录
外部配置总结

最终效果:优先级由高到低,前面的覆盖后面的
命令行>包外 config 直接子目录>包外 config 目录>包外根目录>包内目录- 同级比较
Profiles 配置>Application 配置Properties 配置>YAML 配置
规律总结:最外层的最优先
- 命令行 > 所有方式
- 包外 > 包内
/config子目录 > 根目录- Profiles 配置 > Application 配置
- 配置不同就都生效(互补),配置相同则高优先级会覆盖低优先级的配置
导入配置使用
使用 spring.config.import 可以导入额外的配置。
1 | =classpath:/my.properties |
无论以上写法的先后顺序是怎样,my.properties 的值总是优先于直接在文件中编写的 my.property。
属性占位符使用
配置文件中可以使用 ${name:default} 形式取出之前配置过的值。
1 | =MyApp |
JUnit 5 单元测试
整合单元测试
SpringBoot 提供一系列测试工具集及注解方便开发者进行测试。spring-boot-test 提供核心测试能力,spring-boot-test-autoconfigure 提供测试的一些自动配置。值得一提的是,一般只需要导入 spring-boot-starter-test 即可整合单元测试。
1 | <dependency> |
spring-boot-starter-test 默认提供了以下库供开发者进行单元测试使用:
使用单元测试
组件测试
直接通过 @Autowired 注入容器中的组件即可进行测试。
1 | import org.junit.jupiter.api.Test; |
特别注意
单元测试类所在包的名称,必须与主启动类所在的包或者其子包的名称相同;否则单元测试类需要通过 @SpringBootTest 注解的 class 属性指定主启动类。
常用注解
提示
JUnit5 的注解与 JUnit4 的注解有所区别,详细说明请参考 官方文档。
@Test: 表示方法是测试方法。但是与 JUnit4 的@Test不同,它的职责非常单一不能声明任何属性,拓展的测试将会由 Jupiter 提供额外测试@ParameterizedTest: 表示方法是参数化测试,下面会有详细介绍@RepeatedTest: 表示方法可重复执行,下面会有详细介绍@DisplayName: 为测试类或者测试方法设置展示名称@BeforeEach: 表示在每个单元测试之前执行@AfterEach: 表示在每个单元测试之后执行@BeforeAll: 表示在所有单元测试之前执行@AfterAll: 表示在所有单元测试之后执行@Tag: 表示单元测试类别,类似于 JUnit4 中的@Categories@Disabled: 表示测试类或测试方法不执行,类似于 JUnit4 中的@Ignore@Timeout: 表示测试方法运行如果超过了指定时间将会返回错误@ExtendWith: 为测试类或测试方法提供扩展类引用
1 | import static org.junit.jupiter.api.Assertions.fail; |
常用断言
| 方法 | 说明 |
|---|---|
| assertEquals | 判断两个对象或两个原始类型是否相等 |
| assertNotEquals | 判断两个对象或两个原始类型是否不相等 |
| assertSame | 判断两个对象引用是否指向同一个对象 |
| assertNotSame | 判断两个对象引用是否指向不同的对象 |
| assertTrue | 判断给定的布尔值是否为 true |
| assertFalse | 判断给定的布尔值是否为 false |
| assertNull | 判断给定的对象引用是否为 null |
| assertNotNull | 判断给定的对象引用是否不为 null |
| assertArrayEquals | 数组断言 |
| assertAll | 组合断言 |
| assertThrows | 异常断言 |
| assertTimeout | 超时断言 |
| fail | 快速失败 |
嵌套测试
JUnit 5 可以通过 Java 中的内部类和 @Nested 注解实现嵌套测试,从而可以更好的把相关的测试方法组织在一起。在内部类中可以使用 @BeforeEach 和 @AfterEach 注解,而且嵌套的层次没有限制。
1 | package com.clay.boot; |
参数化测试
参数化测试是 JUnit5 很重要的一个新特性,它使得用不同的参数多次运行测试成为了可能,也为单元测试带来许多便利。利用 @ValueSource 等注解,指定传入的参数,将可以使用不同的参数进行多次单元测试,而不需要每新增一个参数就新增一个单元测试,省去了很多冗余代码。
@ValueSource: 为参数化测试指定入参来源,支持八大基础类以及 String 类型,Class 类型@NullSource: 表示为参数化测试提供一个null的入参@EnumSource: 表示为参数化测试提供一个枚举入参@CsvFileSource:表示读取指定 CSV 文件内容作为参数化测试入参@MethodSource:表示读取指定方法的返回值作为参数化测试入参(注意方法的返回值需要是一个流)
1 | import org.junit.jupiter.api.Assertions; |
SpringBoot 事件驱动开发
SpringBoot 提供了基于事件驱动的编程模型,允许开发者将代码以应用程序与 IOC 容器之间的事件进行的方式来组织,实现松散耦合和高内聚。在 SpringBoot 事件驱动的过程中,当事件被触发时,IOC 容器会通过 ApplicationEventPublisher 发布事件。事件监听器通过实现 ApplicationListener 接口,并指定其感兴趣的事件类型来响应此事件。SpringBoot 事件驱动支持异步监听,可以在异步环境中执行事件响应函数,达到事件和响应函数的解耦。例如可以基于 SimpleAsyncTaskExecutor 执行器实现简单的异步处理。本节完整的案例代码,可以直接从 GitHub 下载对应章节 spring-boot3-08。
事件驱动使用介绍
SpringBoot 事件驱动开发,依赖应用启动过程生命周期事件感知(9 大事件)、应用运行中事件感知(无数种),详细介绍请看 这里。
- 事件发布:实现
ApplicationEventPublisherAware接口,或者注入ApplicationEventMulticaster - 事件监听:实现
ApplicationListener接口,或者使用@EventListener注解


事件驱动使用场景
SpringBoot 事件驱动的常见使用场景
系统级别:例如在应用启动或关闭时执行一些任务。业务处理:例如用户完成注册时,在后台发送电子邮件或短信等。更改数据或状态:例如在用户完成订单时,将订单数据写入数据库,并发送通知邮件。
SpringBoot 事件监听的常见使用场景
对事件进行处理:如发送邮件,写日志,执行业务逻辑等。事件发布 / 订阅:多个组件可以监听同一事件,每个组件可以以自己独特的方式响应事件,例如使用事件获取数据等。事件模型:自定义 SpringBoot 事件可以成为一个轻量级的消息传递系统。
事件驱动使用案例
这里将模拟用户成功登录后,通过 SpringBoot 的事件驱动模型,分别执行增加用户积分、发送优惠券、记录系统日志等操作。
- 实体类
1 |
|
- 控制器类
1 |
|
- 自定义事件,继承
ApplicationEvent类
1 | public class LoginSuccessEvent extends ApplicationEvent { |
- 定义事件发送器,实现
ApplicationEventPublisherAware接口,获取 IOC 容器中的ApplicationEventPublisher
1 |
|
- 接收事件,实现
ApplicationListener接口(第一种方式)
1 |
|
- 接收事件,使用
@EventListener注解(第二种方式),可以通过@Order注解指定接收事件的顺序
1 |
|
1 |
|
