引言 #
在大型Spring Boot项目中,缓慢的单元测试执行速度常常成为开发效率的瓶颈。以我司项目为例,原本的单元测试套件需要约90秒才能完成,严重影响了开发流程。经过系统性的优化,我们成功将测试时间缩短至18秒,提升了80%的效率。本文将详细介绍这些优化手段及其原理。
优化前的现状分析 #
在优化前,我们的测试套件存在以下问题:
- 每次测试都启动完整的Spring上下文
- 加载了所有自动配置,包括测试中不需要的中间件
- Bean初始化采用饥饿模式,启动时即初始化所有Bean
- 缺乏针对测试环境的JVM优化
系统化优化方案 #
1. 精确控制测试环境 #
1.1 禁用Web环境
默认的@SpringBootTest
会启动完整的Web环境,包括嵌入式Servlet容器。对于不需要Web功能的测试,可以显式禁用:
@SpringBootTest(
classes = ApplicationBootstrap.class,
webEnvironment = SpringBootTest.WebEnvironment.NONE
)
1.2 排除不必要的自动配置
@EnableAutoConfiguration(exclude = {
DubboServiceRegistrationNonWebApplicationAutoConfiguration.class
})
2. 智能初始化策略 #
2.1 延迟初始化(Lazy Initialization)
Spring Boot 2.2+支持延迟初始化,Bean只在首次使用时才初始化:
spring.main.lazy-initialization=true
2.2 使用组件索引加速扫描
添加spring-context-indexer
依赖生成组件索引:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-indexer</artifactId>
<optional>true</optional>
</dependency>
3. 中间件与基础设施优化 #
3.1 禁用服务发现
spring.cloud.service-registry.auto-registration.enabled=false
spring.cloud.discovery.enabled=false
3.2 关闭不必要的中间件
假如你们的中间件可以通过环境变量关闭,可以添加对应的环境变量在单元测试中关闭
-Dmanagement.endpoints.enabled-by-default=false
-Dmanagement.endpoints.web.exposure.exclude=*
-Dmanagement.endpoint.health.enabled=false
-Dmanagement.endpoint.shutdown.enabled=false
-Dmanagement.health.redis.enabled=false
-Dmanagement.health.db.enabled=true
4. JVM级别优化 #
4.1 简化JIT编译
-XX:TieredStopAtLevel=1
4.2 其他JVM优化
-noverify
-Dspring.jmx.enabled=false
完整优化配置示例 #
@SpringBootTest(
classes = ApplicationBootstrap.class,
webEnvironment = SpringBootTest.WebEnvironment.NONE
)
@EnableAutoConfiguration(exclude = {
DubboServiceRegistrationNonWebApplicationAutoConfiguration.class,
})
@ActiveProfiles("test")
public class OptimizedIntegrationTest {
// 测试用例...
}
对应的application-test.properties
:
spring.main.lazy-initialization=true
spring.cloud.service-registry.auto-registration.enabled=false
spring.cloud.discovery.enabled=false
management.endpoints.enabled-by-default=false
management.endpoints.web.exposure.exclude=*
management.endpoint.health.enabled=false
management.endpoint.shutdown.enabled=false
management.health.redis.enabled=false
management.health.db.enabled=true
JVM参数:
-XX:TieredStopAtLevel=1
-noverify
-Dspring.jmx.enabled=false
PS: 默认IDEA运行新的单元测试,其中JVM参数是默认为空的,你可以修改Junit运行模板,或者添加下面maven 插件,将JVM参数和变量都放到 argLine 中
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<argLine>
</argLine>
</configuration>
</plugin>
优化效果对比 #
优化措施 | 优化前耗时 | 优化后耗时 | 节省时间 |
---|---|---|---|
初始状态 | 90秒 | 90秒 | 0秒 |
1. 禁用Web环境 | 90秒 | 82秒 | 8秒 |
2. 禁用服务注册与发现 | 82秒 | 67秒 | 15秒 |
3. 启用延迟初始化 | 67秒 | 52秒 | 15秒 |
4. 禁用非必要中间件 | 52秒 | 40秒 | 12秒 |
5. 使用组件索引 | 40秒 | 32秒 | 8秒 |
6. JVM编译优化 | 32秒 | 27秒 | 5秒 |
7. 其他微调(升级Junit5等) | 27秒 | 18秒 | 9秒 |
深入分析与思考 #
剩余耗时分析 #
优化后仍存在的耗时点:
- Spring Boot启动:6秒(必要的框架初始化)
- 配置中心查询:5秒(如Nacos/Apollo)
- 数据源和中间件:7秒(即使排除自动配置,部分必要连接仍需建立)
后续优化狠活清单:
-
Bean启动整顿计划
准备给中间件和核心Bean上紧发条!现在项目启动就像春运火车站,那些拖后腿的Bean一个拽一个。打算用IDEA的CPU耗时分析当X光机,把启动顺序编排得像交警查超载——谁占着茅坑不拉屎,谁敢摸鱼就优化谁,让项目启动从堵车变飙车! -
代码基因改造工程
是时候给函数式代码做变形手术了!把满世界乱窜的Lambda表达式抓回来,关进面向对象的牢房(啊不,是架构)。先给每个模块安排单元测试当入职体检,等把集成测试这个臃肿大团建拆成敏捷小分队,秒级启动就能跟火箭发射倒计时似的10…9…8…
个人踩坑总结: #
-
AI辅助实战血泪史
现在AI就是个爱吹牛的小助理!我之前想靠它优化项目启动速度,结果被坑惨了——给的方案要么是玄学偏方,要么直接报错。最气人的是它编瞎话脸不红心不跳,明明不知道答案还装专家。现在我看到AI给的方案都忍不住怀疑:这货是不是又在忽悠我?最后还是自己啃Spring源码+用IDEA的CPU性能分析工具,像侦探查案一样揪出耗时的代码,才真正解决问题。 -
AI生存法则
别被AI的学霸人设骗了!这货现在就是个会说话的参考资料库,关键时刻还得靠真本事。想在行业里站稳脚跟,必须修炼成领域大神——AI可以帮你搬砖,但盖房子的大梁还得你自己扛。 -
Java真香警告
最近优化代码悟了:Python是泡面(写起来快吃完就拉倒),Java是老酒(越优化越香)。特别是性能优化时,Java能把机器性能榨出最后一滴油,这种掌控感真的爽! -
AI写作防伪指南
用AI写博客就像开美颜相机——第一眼惊为天人,看久了满屏塑料味!现在看见"综上所述"这种AI八股文就想点右上角,跟闻到食堂菜里的大锅水煮味似的。不过有个神器功能必须夸:文字草图秒变流程图!现在我让AI当排版美工小弟,核心干货自己掌勺。记住啊,AI是给文章打玻尿酸的,不是换头术——该有的知识骨架还得自己长扎实了,咱要的是通俗易懂的真干货,不是朋友圈装X文学!
成长避坑指南 #
- AI老师现形记
之前说AI能培养专家是我天真了!真正的老师会承认"这个我不懂",但AI宁可瞎编也不认怂。现在的AI辅助就像驾校的倒车入库练习杆——撤了杆子照样不会停车。想系统成长?老办法最靠谱:找高手带路!要么花钱买大佬经验,要么死磕行业经典。AI能帮你省点查资料的时间,但要是把它当师父…等着学一肚子错误知识吧!
参考资料: