spring boot 中 @lazy 注解可延迟单例 bean 初始化以加速启动,适用于低使用率、高开销、依赖运行时参数及非核心辅助类;支持类级别和注入点两种用法,底层基于代理机制实现按需加载,但需注意异常延迟暴露、强转失败、循环依赖及测试覆盖等问题。

Spring Boot 默认在启动时就初始化所有单例 Bean,这会让启动变慢,尤其当某些 Bean 初始化耗时高(比如数据库连接池、风控模型、缓存预热等)。@Lazy 注解能精准控制哪些 Bean 推迟到第一次使用时才创建,从而显著缩短启动时间。
哪些 Bean 适合加 @Lazy
不是所有 Bean 都适合懒加载。重点放在以下几类:
- 启动即用率低的组件:如后台定时任务管理器、异步邮件服务、离线报表生成器
- 初始化开销大的资源:数据库连接池(800–2000ms)、远程 Feign 客户端(300–1500ms)、AI 模型加载器
- 依赖运行时参数的 Bean:例如需读取配置中心动态开关、或依赖某个外部服务健康检查结果后才启用的模块
- 非核心路径的辅助服务:如日志归档服务、数据脱敏工具类、Excel 导出模板引擎
@Lazy 的两种典型用法
加在 Bean 定义上,是全局生效;加在注入点上,只影响当前依赖关系:
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。 当用户需要:(1) 编写或审查Java代码 (2) 检查命名/代码规范 (3) 处理异常和日志 (4) 编写单元测试 (5) 安全编码 (6) 数据库设...
-
类级别标注(推荐):
@Service
@Lazy
public class RiskModelService { ... }
这样整个 Bean 在容器启动时不实例化,无论谁注入它,都按需加载。 -
注入点标注(灵活控制):
@Autowired
@Lazy
private RiskModelService riskModelService;
即使 RiskModelService 类本身没加 @Lazy,这个注入也会触发代理机制,延迟其初始化。
懒加载背后的代理机制
加了 @Lazy 后,Spring 不会直接创建真实对象,而是注入一个轻量级代理:
- 代理对象实现了相同接口(或继承同类),但体积极小
- 首次调用任意方法时,才真正执行构造函数和初始化逻辑
- 内部通过 ObjectFactory 获取真实实例,保证线程安全且仅初始化一次
- 如果是字段注入,实际注入的是 CGLIB 或 JDK 动态代理,不是原始类型实例
使用时要注意的几个坑
@Lazy 虽好,但不加思考乱用可能引入新问题:
- 异常暴露延迟:配置错误、NPE、Bean 找不到等问题不会在启动时报,而是在第一次调用时才抛,增加排查难度
-
强转类型失败:代理对象无法直接强转为具体实现类(如
(RiskModelServiceImpl) service),应优先面向接口编程 - 循环依赖场景更复杂:虽然 @Lazy 能缓解部分循环依赖,但可能掩盖设计问题,建议先重构依赖结构
- 测试需覆盖首次调用路径:单元测试中若未触发该 Bean 的方法调用,就测不到它的初始化逻辑和潜在异常










