Spring 懒加载实现全解析:让你的应用启动快人一步
在实际项目开发中,我们可能遇到这样的场景:应用启动时,Spring 容器会迫不及待地创建所有单例 Bean,即使有些 Bean 在很长一段时间内都用不到。这不仅拖慢了启动速度,还占用了宝贵的内存。Spring 的"懒加载"(Lazy Initialization)正是为了解决这个问题而生。今天这篇博客,带你从概念到实现,再到原理,彻底玩转 Spring 懒加载。
一、什么是懒加载?
懒加载 是一种设计思想:等到真正需要某个资源的时候,才去创建或加载它 。
在 Spring 容器中,默认的行为是 迫切加载 (Eager Initialization)------ 所有单例 Bean 会在容器启动阶段完成实例化与依赖注入。而开启懒加载后,单例 Bean 的创建时机被推迟到第一次被请求时(如 getBean() 或依赖注入到另一个 Bean)。
下面这张图直观对比了两种策略的区别:

二、如何开启 Spring 懒加载?
Spring 提供了非常灵活的配置方式,可以用注解,也可以用 XML,还能做全局开关。
1. 使用 @Lazy 注解
最直接的方式,在需要懒加载的 Bean 上标注 @Lazy。
java
@Component
@Lazy
public class EmailService {
public EmailService() {
System.out.println("EmailService 被创建了!");
}
public void send(String message) {
System.out.println("发送邮件:" + message);
}
}
在配置类里搭配 @Bean 使用:
java
@Configuration
public class AppConfig {
@Bean
@Lazy
public EmailService emailService() {
return new EmailService();
}
}
此时,Spring 容器启动时并不会创建 EmailService,直到有人调用 context.getBean(EmailService.class) 或它被注入到其他 Bean 并被使用时才会实例化。
懒加载也能用在注入点 :如果某个 Bean 本身不是懒加载,但想让它依赖的 Bean 延迟初始化,可以在注入点加 @Lazy。
java
@Component
public class NotificationManager {
@Autowired
@Lazy
private EmailService emailService;
public void notifyUser() {
emailService.send("欢迎注册"); // 此时才创建 EmailService
}
}
2. 通过 XML 配置懒加载
在传统 XML 配置中,可以给 <bean> 标签添加 lazy-init="true" 属性。
xml
<bean id="emailService" class="com.example.EmailService" lazy-init="true" />
如果想全局默认懒加载,在 <beans> 根元素加上 default-lazy-init="true":
xml
<beans default-lazy-init="true">
<bean id="emailService" class="com.example.EmailService" />
<bean id="smsService" class="com.example.SmsService" />
</beans>
但要注意,如果某个 Bean 显式设置了 lazy-init="false",则以自身设置为准。
3. Spring Boot 全局开关
在 Spring Boot 应用中,可以在 application.properties 里添加一行配置:
properties
spring.main.lazy-initialization=true
这会让所有 Bean 都默认懒加载。如果有些 Bean 必须立即初始化,可以单独加上 @Lazy(false) 覆盖全局设置。
三、懒加载的内部原理
知其然,也要知其所以然。Spring 是如何实现懒加载的?核心围绕 BeanFactory 的创建流程。

Spring 在读取 BeanDefinition 时,会检查 lazyInit 属性。若为 true,则在容器刷新阶段的 finishBeanFactoryInitialization() 中跳过该 Bean 的实例化。真正触发创建的地方,是 AbstractBeanFactory 的 getBean() 方法,其中调用了 getSingleton(),若缓存中不存在,则会走 createBean() 流程,并最终放入单例缓存。
小陷阱:懒 Bean 被非懒 Bean 依赖
如果一个懒加载的 Bean 被另一个非懒加载的 Bean 注入了,那么懒加载会失效,因为它会在容器启动时作为依赖被提前实例化。这是 Spring 依赖解析的必然结果,使用时务必注意。
四、懒加载实战演示
假设我们有如下三个组件:
OrderService:急切加载EmailService:懒加载SmsService:急切加载,但依赖EmailService
java
@Component
public class OrderService {
public OrderService() {
System.out.println("OrderService 实例化");
}
}
@Component
@Lazy
public class EmailService {
public EmailService() {
System.out.println("EmailService 实例化");
}
}
@Component
public class SmsService {
@Autowired
private EmailService emailService;
public SmsService() {
System.out.println("SmsService 实例化");
}
}
启动容器,你会看到控制台输出:
OrderService 实例化
EmailService 实例化
SmsService 实例化
咦?EmailService 明明是懒加载,为什么被创建了?因为 SmsService 是迫切加载,它又依赖了 EmailService,为了完成依赖注入,容器只好提前实例化 EmailService。
解决办法 :在 SmsService 的注入点上也加 @Lazy,这样注入的是懒代理,不会立刻触发 EmailService 的实例化。
java
@Autowired
@Lazy
private EmailService emailService;
这样再运行,控制台输出:
OrderService 实例化
SmsService 实例化
EmailService 没有被创建,直到 SmsService 中真正调用 emailService.send(...) 时才会初始化。
五、何时该用懒加载?优缺点一览
优点
- 加快启动速度:减少初始化时间,尤其适合微服务、Serverless 等对冷启动敏感的场景。
- 节省内存:不立即使用的 Bean 不占用资源。
- 按需加载:大型应用中,部分模块可能从不被访问,懒加载避免无用开销。
缺点
- 隐藏错误:配置错误或依赖缺失在启动时不会被发现,延迟到运行时才暴露,增加排查难度。
- 首次调用延迟:第一次请求时会触发 Bean 创建,可能带来较高的响应延迟(冷启动 spike)。
- 复杂性:需要小心处理依赖关系,避免意外的迫切初始化。
推荐实践
- 开发环境可全局关闭懒加载,尽早暴露配置问题。
- 生产环境可根据需要开启全局懒加载,并用
@Lazy(false)将核心 Bean(如数据库连接池、监控端点)标记为迫切加载。 - 微服务架构下,Spring Boot 全局懒加载是一个常见优化手段。
六、总结
Spring 的懒加载通过 @Lazy 注解、XML 属性或 Boot 全局配置即可轻松实现。它的核心原理是延迟 Bean 的创建时机,直到第一次被请求。虽然能显著提升启动速度,但也会带来错误延时暴露等问题,因此需要根据实际情况审慎选择。
掌握懒加载,是在大型应用与云原生架构下进行启动优化的必修课。希望这篇博客能帮你透彻理解并灵活运用这一特性。如果觉得有帮助,欢迎点赞收藏,也欢迎在评论区交流你的实践心得!