在 Spring Boot 项目里,容器启动时会默认把上下文中几乎所有的单例 Bean 提前实例化并完成依赖装配。当工程里包含大量涉及数据库连接池、Redis 客户端或者复杂算法初始化的组件时,这种饿汉式加载会让启动过程变得很慢。@EnableLazy 是 Spring 框架提供的用于开启延迟初始化的注解,把它加在配置类上,可以让对应范围内的 Bean 推迟到真正被使用的时候才创建。在整合 Spring Boot 的过程中,合理地使用这个注解,是优化启动性能的一种直接手段。

@EnableLazy 的基本用法与整合位置
@EnableLazy 本身来自 Spring 的 org.springframework.context.annotation 包,它作为一个元注解组合了 @Configuration 的能力,并导入了处理懒加载的后置处理器。在 Spring Boot 应用中,我们通常不会单独写一个被 @EnableLazy 标注的配置类,而是把它放在主启动类或者某一层业务配置上。需要注意,Spring Boot 2.2 之后也提供了 spring.main.lazy-initialization=true 的全局属性,但 @EnableLazy 的优势在于可以精确到某一个 @Configuration 类所对应的 Bean 定义区域。
下面是一段典型的整合代码,我们在数据访问层的配置类上使用 @EnableLazy,使得该配置中定义的 Mapper 或相关仓储 Bean 不被提前初始化:
package com.example.demo.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableLazy;
@Configuration
@EnableLazy
public class DataAccessConfig {
// 此处定义的 Bean 在容器启动阶段不会实例化
// 只有当其他组件首次注入或使用它们时才会创建
}
从容器生命周期角度看,@EnableLazy 实际是给对应的 BeanDefinition 设置了 isLazyInit 的标记。在 AbstractApplicationContext 的 finishBeanFactoryInitialization 方法中,Spring 会跳过那些被标记为懒加载的单例 Bean。这意味着即便你的工程里有上百个 Bean,只要它们处在这个配置类的扫描或注册范围内,启动时就只会注册定义而不会占用实例化时间。
与全局懒加载配置的差异及选型
很多开发者在搜 Spring Boot 优化启动时间时,会直接打开 application.properties 写下 spring.main.lazy-initialization=true。这种做法和 @EnableLazy 最大的不同在于作用域。全局配置会影响整个应用上下文中的所有单例 Bean,而 @EnableLazy 仅影响它所在配置类及其导入的 Bean。若你的系统里有部分 Bean 必须在启动时完成预热,比如监听端口的 Web 服务器、健康检查指示器,那么全局懒加载可能会让这些关键组件延迟就绪,从而导致健康检查失败或第一批请求极慢。
通过对比可以更清楚地看到两者的适用边界:
| 方式 | 作用范围 | 配置复杂度 | 风险点 |
|---|---|---|---|
| 全局 lazy-initialization | 整个 ApplicationContext | 一行属性 | 核心基础设施延迟导致启动后抖动 |
| @EnableLazy 注解 | 特定配置类区域 | 需拆分配置 | 范围划分不清时部分 Bean 仍早加载 |
在实际整合中,推荐将重型、非核心的组件配置独立成带有 @EnableLazy 的配置类,而把 Web、监控等基础配置留在默认饿汉加载中。这样既享受了延迟初始化带来的启动加速,又不会破坏 Spring Boot 内嵌服务器的正常就绪流程。需要特别留意,被 @ComponentScan 扫到的普通 @Service 若不在该配置类名下,是不会继承这个懒加载属性的。
延迟初始化下的循环依赖与避坑实践
使用 @EnableLazy 之后,一个容易忽视的问题是循环依赖的表象变化。在默认饿汉加载时,Spring 会通过提前暴露半成品 Bean 来解决构造器之外的循环依赖;但当你把其中一侧设为懒加载,这个 Bean 在启动阶段根本不会被创建,于是循环依赖的报错可能会消失,转而变成第一次调用时才抛出 BeanCurrentlyInCreationException。这种延迟暴露的故障在测试阶段很难发现,往往要到生产环境真实流量进来才显现。
为了避免这类隐患,应当在开启 @EnableLazy 的同时,梳理被延迟 Bean 之间的引用关系。如果 A 和 B 互相依赖,且 A 被懒加载,那么首次获取 A 时会创建 A,接着填充属性时去拿 B,而 B 若不是懒加载且已经早先创建好,则没有问题;但如果 B 也依赖 A 的某一方法并返回新实例,就可能触发嵌套创建。下面示例展示如何用 @Lazy 注解配合 @EnableLazy 做细粒度控制:
@Service
public class OrderService {
private final PaymentService paymentService;
// 在注入点也声明懒加载,确保 PaymentService 不会在 OrderService 创建时立刻被拉起
public OrderService(@Lazy PaymentService paymentService) {
this.paymentService = paymentService;
}
public String createOrder() {
return paymentService.pay() + ":done";
}
}
另一个实践要点是监控延迟 Bean 的首次实例化耗时。由于它们被推迟到业务请求阶段,若某个 Bean 内部要建连远程服务,第一次接口调用就会承担这部分成本。建议配合 Spring Boot 的 Metrics 或简单的日志,在 Bean 的 @PostConstruct 中打印耗时,确认延迟初始化没有把启动慢转化成了接口慢。只有把范围控制合理、依赖梳理清楚,@EnableLazy 在 Spring Boot 整合中才真正起到既快又稳的作用。
Spring_BootEnableLazyBean_lazy_initialization修改时间:2026-08-13 22:54:31