Spring `@Lazy` 注解技术文档

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.propertiesapplication.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. 最佳实践建议

  1. 优先用于启动优化 :将启动阶段用不到但初始化昂贵的 Bean(如报表引擎、文件处理组件)标记为 @Lazy,以获得客观的启动速度提升。
  2. 局部而非全局:避免开启全局懒加载,针对具体 Bean 按需加注,保持错误尽早暴露的原则。
  3. 循环依赖的最后手段 :遇到循环依赖时,首先考虑解耦设计,如引入中间层、事件机制或拆分职责;仅在无法重构时使用 @Lazy 打破循环。
  4. 结合条件注解 :可配合 @ConditionalOnProperty 等条件注解,使 Bean 的创建与属性开关联动,实现更灵活的按需加载。

6. 总结

@Lazy 是 Spring 懒加载机制的核心注解,通过将 Bean 的实例化推迟到首次使用时,在加速启动、节省资源、打破循环依赖 三个方面发挥关键作用。使用时需要平衡启动优化与运行时错误暴露之间的关系,并避免将其作为掩盖设计缺陷的常规工具。合理、局部地使用 @Lazy 可以有效提升 Spring 应用的启动性能与资源利用率。

相关推荐
阿波罗尼亚6 小时前
桌面应用开发技术:NetBeans RCP / Eclipse RCP / JavaFX / Electron / Qt / Flutter Deskto
java·eclipse·electron
echola_mendes6 小时前
InfluxDB(四)——动态 Field/Tag 实现多类型设备统一接入的完整实践指南
java·后端·struts
SuperherRo6 小时前
服务攻防-Java组件安全&Solr搜索&Shiro鉴权&Log4j日志&JDK高版本绕过&CVE历史漏洞
java·log4j·solr·shiro·cve
Cyan_RA96 小时前
SpringMVC REST 详解
java·spring·mvc·springmvc·restful·jquery·jsp
skilllite作者6 小时前
Warp 新手极速上手与部署指南
java·前端·笔记·安全·agentskills
许彰午6 小时前
我手写了一个 Java 内存数据库(四):索引引擎、SQL 解析与总结
java·数据库·sql
TO_ZRG6 小时前
Android Broadcast Receiver完全入门指南
java·后端·spring
Knight_AL6 小时前
使用 CyclicBarrier + 自定义线程池实现 SpringBoot 并行报表(完整性能对比)
java·spring boot·后端
人道领域7 小时前
【LeetCode刷题日记】347.前k个高频元素
java·数据结构·算法·leetcode