Spring Boot 启动慢,我排查了一圈
起因
项目启动从 20 秒慢慢涨到快 90 秒,本地改一行代码重启一次,等得人想砸键盘。一开始以为是自己电脑不行,后来发现测试环境也一样,才开始认真查。
这篇记一下排查过程和最后动的东西。
先量,别猜
第一步不是改代码,是搞清楚时间花在哪。
Spring Boot 启动日志里默认有耗时,但不够细。我是加了个 ApplicationStartup 的监听,或者简单点,直接在 main 里打时间戳:
public static void main(String[] args) {
long start = System.currentTimeMillis();
SpringApplication.run(DemoApplication.class, args);
System.out.println("启动耗时: " + (System.currentTimeMillis() - start) + "ms");
}
这只能看总时长。要看每个 Bean 的初始化时间,我开了 -Ddebug 不够,最后用的是 BufferingApplicationStartup:
SpringApplication app = new SpringApplication(DemoApplication.class);
app.setApplicationStartup(new BufferingApplicationStartup(2048));
app.run(args);
然后配合 /actuator/startup 端点,能看到每个启动步骤的耗时,哪些 Bean 慢一眼就出来了。
查出来的几个大头
第一个,扫描范围太大。 启动类在 com.example 根包下,@SpringBootApplication 默认扫整个子树,连测试用的、废弃的类都扫进来了。而且项目里还引了一堆 starter,每个都带自己的自动配置,条件注解挨个评估一遍也要时间。
第二个,某个 starter 拖了后腿。 排查时发现有个数据源相关的自动配置,明明没配数据库,它还在初始化连接池、跑健康检查。这种就是典型的“引了用不上”。后来在 application.yml 里排掉:
spring:
autoconfigure:
exclude:
- com.example.some.AutoConfiguration
Spring Boot 3 里这个属性改叫 spring.autoconfigure.exclude 了,写法一样。
第三个,@PostConstruct 里干重活。 有个 Service 在 @PostConstruct 里加载本地缓存文件,文件不小,每次启动都读一遍。改成懒加载,第一次访问的时候再初始化,启动时间直接少了十来秒。
第四个,JPA / Hibernate 的 ddl-auto。 开发环境开着 update,启动时 Hibernate 要连库比对表结构,库越大越慢。这个生产环境本来就不该开,开发环境也改成了 none,需要建表就用迁移脚本。
顺手做的几件事
- 关掉不必要的日志级别。
logging.level.root=INFO就行,DEBUG 开着的时候光是日志输出就能拖慢几秒。 - 懒初始化。
spring.main.lazy-initialization=true能明显提速,但要注意:Bean 报错会推迟到第一次使用时才暴露,本地开发可以开,线上慎用。 - 排除无用依赖。
mvn dependency:tree看一眼,好几个引进来根本没用过的包,删掉之后启动和打包都快了点。
关于懒初始化,多说两句
lazy-initialization 我一开始全开了,启动确实快,但踩了个坑:某个 Bean 依赖的配置项写错了,以前启动就报错,开了懒加载之后要等接口调过去才炸。本地调试还行,测试环境就不合适了。
后来改成只对特定 Bean 加 @Lazy,比如那些初始化重、但启动时用不到的。全局开关还是关着。
小结
启动慢基本就这几个来源:扫描范围、自动配置、初始化逻辑、数据库连接、日志。排查顺序我是先量总时长,再看步骤耗时,定位到具体 Bean 再动。
改完之后从 90 秒降到 30 秒左右,本地热重启快了不少。剩下的 30 秒里有一大半是数据库连接和框架本身的开销,再压就得动架构了,暂时没那个必要。
先记到这,后面再有新发现接着补。
- 点赞
- 收藏
- 关注作者
评论(0)