Spring @Lazy 注解技术文档
| 文档信息 | 内容 |
|---|---|
| 文档标题 | Spring @Lazy 注解技术说明 |
| 版本号 | v1.0 |
| 创建日期 | 2026-04-30 |
| 适用范围 | Spring Framework 4.x / 5.x / 6.x 及以上 |
| 关联技术 | Spring IoC 容器、依赖注入、循环依赖 |
1. 概述
@Lazy 是 Spring 框架提供的一个核心注解,用于声明某个 Bean 应该采用**延迟初始化(懒加载)**策略。
默认情况下,Spring 容器在启动时会主动创建并装配所有单例 Bean(饿汉式初始化);加上 @Lazy 后,容器的行为变为:只在首次实际需要该 Bean 时才触发实例化,从而减少启动阶段的计算与资源消耗,并可作为打破循环依赖的辅助手段。
2. 核心作用
2.1 打破循环依赖
当两个或多个 Bean 相互引用时,若均采用立即初始化,容器会陷入死循环并抛出 BeanCurrentlyInCreationException。
在依赖链的某一环节使用 @Lazy,Spring 会先注入一个代理对象,使依赖注入能够完成;真正的目标 Bean 将在首次方法调用时才被实例化,从而安全地解开循环。
2.2 缩短应用启动时间
某些 Bean 的初始化过程可能十分耗时,例如:
- 建立数据库连接池
- 加载大型配置文件到内存
- 初始化第三方 SDK 客户端
如果这些 Bean 在应用启动阶段并不被立即使用,标记@Lazy可以将其初始化推迟到真正需要时,从而显著降低启动延迟。
2.3 按需加载资源
对于仅在特定功能分支或特定条件下才会被访问的 Bean,使用懒加载可以避免应用启动时浪费内存与 CPU 资源,实现更精细的运行时开销控制。
3. 使用方式
3.1 在 @Bean 方法上使用
java
@Configuration
public class DataSourceConfig {
@Bean
@Lazy
public DataSource heavyDataSource() {
// 只有在首次请求该 Bean 时才会执行此方法
return new HikariDataSource(complexConfig());
}
}
3.2 在组件类上使用
java
@Component
@Lazy
public class ReportGenerator {
public ReportGenerator() {
System.out.println("ReportGenerator 被创建");
}
}
注意:即便类上标注了 @Lazy,如果该 Bean 被一个未加 @Lazy 的 Bean 无条件注入,它仍然会在应用启动时被创建。
3.3 在注入点上使用
java
@Service
public class OrderService {
private final ReportGenerator reportGenerator;
// 在构造函数注入时添加 @Lazy
public OrderService(@Lazy ReportGenerator reportGenerator) {
this.reportGenerator = reportGenerator;
}
}
- 这种方式使得
OrderService本身可以立即初始化,而ReportGenerator的实际创建延迟到reportGenerator的方法被调用时。 @Lazy也可用于@Autowired字段或 setter 方法。
3.4 全局启用懒加载(谨慎使用)
在 application.properties 或 application.yml 中设置:
properties
spring.main.lazy-initialization=true
- 该选项会将容器内所有 Bean 的默认行为改为懒加载。
- 通常不建议在生产环境开启,因为它可能隐藏启动阶段本应暴露的配置错误或缺失依赖。
4. 行为细节与注意事项
4.1 代理机制
当 @Lazy 作用于注入点时,Spring 会为该依赖创建一个代理对象,并将其注入。
- 首次调用代理的任何方法时,代理会触发目标 Bean 的真正初始化,然后再将调用转发给实际对象。
- 因此,因延迟初始化而带来的"首次调用性能开销"是存在的,对延迟敏感的场景需评估。
4.2 与 @Scope("prototype") 的区别
@Lazy只影响初始化时机,不影响作用域;默认仍然是单例(Singleton)。@Scope("prototype")则使每次请求都创建新实例,两者的控制维度不同。
4.3 启动时的依赖分析
如果一个懒加载 Bean 依赖于其他必须立即初始化的基础设施(如配置属性、环境变量),该依赖关系不受影响------基础设施仍会先被初始化,懒加载只是推迟了目标 Bean 本身的构建。
4.4 潜在问题
- 问题隐藏:启动阶段不会发现缺失的必要 Bean 或配置错误,直到运行时首次调用才会暴露,延后了错误暴露时机。
- 代理类型限制 :若目标类是
final类型,Spring 默认使用 CGLIB 代理会失败;此时需将proxyTargetClass设为false或使用接口代理。 - 循环依赖复杂度 :虽然
@Lazy可以解决循环依赖,但不代表循环依赖是好的设计,应优先考虑重构依赖关系。
5. 最佳实践建议
- 优先用于启动优化 :将启动阶段用不到但初始化昂贵的 Bean(如报表引擎、文件处理组件)标记为
@Lazy,以获得客观的启动速度提升。 - 局部而非全局:避免开启全局懒加载,针对具体 Bean 按需加注,保持错误尽早暴露的原则。
- 循环依赖的最后手段 :遇到循环依赖时,首先考虑解耦设计,如引入中间层、事件机制或拆分职责;仅在无法重构时使用
@Lazy打破循环。 - 结合条件注解 :可配合
@ConditionalOnProperty等条件注解,使 Bean 的创建与属性开关联动,实现更灵活的按需加载。
6. 总结
@Lazy 是 Spring 懒加载机制的核心注解,通过将 Bean 的实例化推迟到首次使用时,在加速启动、节省资源、打破循环依赖 三个方面发挥关键作用。使用时需要平衡启动优化与运行时错误暴露之间的关系,并避免将其作为掩盖设计缺陷的常规工具。合理、局部地使用 @Lazy 可以有效提升 Spring 应用的启动性能与资源利用率。