🔍 第一步:定位启动瓶颈
排查启动慢的问题,核心是找到时间花在哪里了。以下几种方式由易到难:
开启启动耗时日志
在 application.properties 中添加:
spring.main.startup=buffered
或者引入 Actuator 的 startup 端点,访问 /actuator/startup,可以看到每个 Bean 的初始化耗时,快速定位慢 Bean。
查看自动配置报告
在配置文件中设置日志级别:
logging.level.org.springframework.boot.autoconfigure=debug
启动后日志中会出现 ==== Conditions evaluation report ====,列出所有自动配置类的匹配/排除情况,帮你发现加载了哪些不需要的配置。
使用开源分析工具
推荐 Spring Startup Analyzer,它会自动采集启动过程数据,生成交互式 HTML 分析报告,直观展示每个阶段的耗时。
🎯 第二步:常见慢点及优化方案
根据定位结果,以下是启动慢的常见原因和对应解决办法:
过多的自动配置
项目依赖多时,Spring Boot 会尝试为各类依赖做自动配置。排除不需要的:
@SpringBootApplication(exclude = { ElasticsearchAutoConfiguration.class, RabbitAutoConfiguration.class})
或者在配置文件中排除:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchAutoConfiguration
大量 Bean 初始化耗时
-
开启懒加载:让 Bean 在第一次使用时才创建,而不是启动时一次性全部初始化:
spring.main.lazy-initialization=true -
单个 Bean 懒加载:对个别耗时 Bean 加
@Lazy注解,比如有@Async线程池初始化时加载外部资源的 Bean。
数据源/连接池初始化慢
数据库连接池(如 Redis、MySQL)启动时预创建大量连接是常见瓶颈。例如 Redis 配置了最大连接数 100,启动时就创建 100 个连接,可以改为惰性初始化:
spring.data.redis.lettuce.pool.min-idle=0
组件扫描范围过大
默认 @ComponentScan 会扫描启动类所在包及所有子包,加载太多不必要的 Bean。可以缩小扫描范围:
@SpringBootApplication(scanBasePackages = {"com.example.app"})
依赖过多
仔细审查 pom.xml,去除不必要的依赖。依赖越多,类加载和资源扫描的时间越长。
⚡ 第三步:进阶优化手段
如果以上基础优化后仍不理想,可以考虑:
-
优化 JVM 参数:增大初始堆内存(
-Xms)和最大堆内存(-Xmx),选择合适的垃圾回收器(如 G1GC),减少启动时的内存压力。 -
切换 Servlet 容器:将默认的 Tomcat 替换为 Undertow,在内存占用和启动速度上通常表现更优。
-
添加 spring-context-indexer:编译时生成静态索引文件,启动时直接使用,跳过类路径扫描:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-indexer</artifactId> <optional>true</optional></dependency> -
Bean 异步初始化:使用
spring-async-bean-starter等工具,将无依赖关系的 Bean 并行初始化,实测可降低 50%-60% 的启动时间。
📌 总结排查流程
- 先量化:用 Actuator startup 端点或 Spring Startup Analyzer 拿到每个 Bean 的耗时数据
- 找 Top N 慢 Bean:重点关注数据源连接池、外部服务调用、
@PostConstruct方法 - 对症下药:懒加载、排除无用配置、缩小扫描范围、优化连接池参数
- 进阶手段:JVM 调优、异步初始化、切换容器
按照这个流程走一遍,90 秒的启动时间通常可以压缩到 20-30 秒以内。