导读:本期聚焦于叶知晏创作的《Spring Boot如何开启懒加载?@Lazy注解与lazy-initialization配置详解》,敬请观看详情。为什么Spring Boot应用启动时要把所有Bean一次性初始化完?能不能让Bean在第一次被使用时才创建?本文围绕Spring Boot的懒加载机制展开,详细讲解spring.main.lazy-initialization全局配置的用法,分析@Lazy注解在类、方法、注入点三个层面的工作原理,并对比懒加载带来的启动速度提升与潜在风险。文中还给出禁用特定Bean懒加载、结合@DependsOn控制初始化顺序的实战示例,帮助你在缩短启动时间和保证运行时稳定性之间做出合理取舍。

Spring Boot应用启动慢是不少团队都遇到过的问题,尤其在微服务场景下,一个服务动辄定义几百个Bean,容器启动阶段要把它们全部实例化,耗时自然水涨船高。Spring从底层就提供了懒加载能力,让Bean推迟到第一次真正被使用时才初始化。Spring Boot 2.2之后更是提供了全局开关spring.main.lazy-initialization,一行配置就能改变整个应用的初始化策略。本文将系统讲解这套机制的原理、用法和注意事项。

一、懒加载的基本原理与全局配置

Spring容器默认的行为是「饿汉式」的:在refresh()阶段的finishBeanFactoryInitialization步骤中,容器会遍历所有非懒加载的单例Bean定义,逐个调用getBean完成实例化、依赖注入和初始化回调。这意味着哪怕某个Bean在整个应用生命周期里只被调用一次,它在启动时也会被完整创建。

懒加载的原理并不复杂:Bean定义上的lazyInit属性被设置为true后,容器启动时会跳过它,只在第一次有代码请求该Bean时才走完整的创建流程。Spring Boot 2.2引入的全局配置如下:

spring:
  main:
    lazy-initialization: true

打开这个开关后,所有Bean默认都变成懒加载,应用启动时间通常能明显缩短。可以通过下面的属性对特定Bean排除在外,保持饿汉式初始化:

spring:
  main:
    lazy-initialization: true
    lazy-initialization-exclude:
      - com.example.config.WarmUpBean
      - "*.HealthIndicator"

需要强调的是,全局懒加载并不会影响自动配置类本身的解析时机,它影响的是Bean的实例化时机,这一点后面会结合源码再展开。

二、@Lazy注解的三种使用姿势

在全局开关出现之前,控制懒加载的主要手段是@Lazy注解。它可以出现在三个位置,效果各有差异。

第一种是标注在@Component及其派生注解的类上,表示该Bean默认懒初始化:

@Component
@Lazy
public class ReportGenerator {
    public ReportGenerator() {
        System.out.println("ReportGenerator 被创建");
    }
}

第二种是标注在@Configuration类中的@Bean方法上,效果相同。第三种比较容易被忽略:标注在注入点上。此时Spring会注入一个代理对象,而不是目标Bean本身,真正的初始化被推迟到代理方法第一次被调用时:

@Service
public class OrderService {

    private final ReportGenerator reportGenerator;

    // 注入点使用@Lazy,注入的是CGLIB代理
    public OrderService(@Lazy ReportGenerator reportGenerator) {
        this.reportGenerator = reportGenerator;
    }

    public void monthlyReport() {
        // 只有执行到这里,ReportGenerator 才真正被创建
        reportGenerator.generate();
    }
}

这种方式非常实用。假设某个Service依赖一个初始化代价昂贵的组件,但你不想让这个组件拖慢整个Bean的构建,就可以在构造器参数或字段上加@Lazy,把代价延后到真正调用时。

另外,@Lazy还可以用在@Configuration类上,效果是配置类中的所有@Bean都变成懒加载。如果同时指定了@Lazyvaluefalse,则可以覆盖全局配置,强制某个Bean饿汉式初始化,这正好和前面的lazy-initialization-exclude形成两种互补方案。

三、懒加载的潜在风险与初始化顺序问题

懒加载不是免费的午餐,最大的代价是问题暴露时机后移。原本在启动阶段就会暴露的依赖缺失、循环依赖、配置错误,现在被推迟到了运行时第一次请求,可能导致某个接口在上线后才突然报500错误。对健壮性要求高的系统,开启全局懒加载前务必配合完善的健康检查和预热机制。

第二个风险是初始化顺序不再确定。Bean的创建顺序由实际使用顺序决定,如果某些Bean在初始化逻辑中隐式依赖了其他Bean先完成初始化(比如依赖静态状态、依赖@PostConstruct的执行先后),懒加载可能打乱这个顺序。解决办法是用@DependsOn显式声明依赖关系:

@Component
@Lazy
@DependsOn("cacheWarmer")
public class QueryService {
    // QueryService 创建前,确保 cacheWarmer 已初始化
}

第三类容易被忽视的Bean是定时任务、消息监听器这类「没有人主动调用、必须自己跑起来」的组件。它们的生命周期依赖容器启动事件触发,多数情况下框架会通过事件机制保证它们正常启动,但如果自定义的初始化逻辑依赖启动阶段立即执行,就要确认懒加载是否影响了预期行为,必要时通过exclude列表排除。

四、实战建议:什么时候该用懒加载

对启动速度敏感的场景,比如Serverless函数计算、开发环境频繁重启、大规模微服务批量发布,全局懒加载收益明显,可以把启动时间压缩到原来的几分之一。而对常驻的、流量稳定的传统服务,饿汉式初始化反而更安全,问题在启动时就暴露,避免运行时惊喜。

一个比较均衡的实践是:默认不开全局开关,只对明确知道初始化昂贵、使用频率低的Bean单独加@Lazy;或者反过来,开全局开关但排除核心链路Bean,并在发布后通过预热接口主动触发关键Bean的初始化。这样既能缩短启动时间,又能保证核心功能的第一次请求不会因为Bean冷启动而变慢。

最后提醒一点:懒加载和@Scope("prototype")是两个不同维度的概念,前者控制「何时创建」,后者控制「创建几份」,二者可以组合使用,不要混淆。理解了Spring容器对Bean定义与Bean实例的两级管理模型,懒加载的一切行为就都能推导出来了。

Spring Boot懒加载@Lazy注解lazy-initialization修改时间:2026-08-31 07:04:46

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。