Spring Boot 启动慢主因是Bean扫描与初始化而非注入本身,优化需精简扫描范围、避免循环依赖、按需加载Bean并监控耗时。

Spring Boot 的依赖注入本身性能很好,启动阶段的耗时主要来自 Bean 扫描、定义注册和实例化过程,而非注入动作本身。真正影响响应速度或启动时间的,往往是注入方式选择不当、循环依赖处理粗暴、或大量非必要 Bean 被加载。优化核心不是“少用 @Autowired”,而是让容器更聪明地加载、解析和组装 Bean。
精简扫描范围,减少 Bean 定义数量
Spring 启动时默认扫描整个包路径,遇到 @Component、@Service 等注解就解析成 Bean 定义——哪怕你根本不会用到它。这是启动慢的主因之一。
- 用 @ComponentScan(basePackages = "com.example.core") 明确限定扫描路径,避开 test、config、model 等无关子包
- 避免在启动类上使用通配符扫描(如 basePackages = "com.example"),尤其当项目含多个模块时
- 对第三方 starter 中不需要的自动配置,通过 spring.autoconfigure.exclude 排除,例如:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
慎用构造器注入 + 循环依赖,优先用 @Lazy 解耦
构造器注入虽推荐,但两个 Service 构造器互相引用会触发早期创建冲突。Spring Boot 2.6+ 默认禁止循环依赖,硬开 spring.main.allow-circular-references=true 可能导致未初始化完成的 Bean 被调用。
- 在其中一个依赖参数上加 @Lazy,让注入点拿到代理对象,首次调用时才真正初始化目标 Bean
- 不推荐为解循环而改用字段注入(@Autowired private XxxService)——破坏不可变性且掩盖设计问题
- 更治本的做法是重构:把共用逻辑抽成独立 Service,或引入事件/回调机制替代强依赖
按需加载 Bean,避免“全量初始化”
很多 Bean 实际只在特定场景下使用(如定时任务、管理端接口、异步通知),却在应用启动时就被实例化,白白消耗内存与 CPU。
- 对非核心功能 Bean 加 @ConditionalOnProperty,例如:
@ConditionalOnProperty(name = "feature.async-enabled", havingValue = "true") - 用 @Scope("prototype") 替代单例,适用于短生命周期、状态隔离的对象(注意:不能用于被其他单例 Bean 直接持有)
- 将部分初始化逻辑后移到 ApplicationRunner 或 CommandLineRunner 中执行,延迟到端口暴露之后
监控注入链路,定位真实瓶颈
别猜,用数据说话。Spring Boot Actuator + Micrometer 可暴露 Bean 创建耗时指标。
- 添加依赖:
spring-boot-starter-actuator和micrometer-registry-prometheus - 开启端点:management.endpoints.web.exposure.include=beans,metrics,threaddump
- 访问 /actuator/metrics/startup.time 查看各阶段耗时,重点关注
context.refresh和bean.instantiation - 结合 SpringApplicationRunListener 自定义监听器,打印每个 Bean 初始化耗时,快速锁定“重量级 Bean”



















