当前位置: 首页 > article >正文

深入理解 Spring 的 Lazy Loading:原理、实现与应用场景

延迟加载(Lazy Loading)是 Spring 容器管理 Bean 的一种策略,指 只有在需要时(调用 getBean() 方法获取 Bean 时)才会实例化该 Bean。这是 Spring 提供的一种优化机制,用于提高启动效率和降低资源占用。


1. 延迟加载的含义

  • 在延迟加载模式下,Spring 容器初始化时不会立即实例化所有 Bean,而是等到真正需要使用时(即调用 getBean() 方法时),才创建 Bean 实例。
  • 如果不启用延迟加载(非 Lazy 模式),则所有单例(singleton) Bean 会在容器启动时立即实例化。

2. 延迟加载的优点

  1. 节省资源:

    • 容器启动时不需要加载和创建所有 Bean,启动速度更快。
    • 避免不必要的对象实例化,降低内存占用,尤其是对于未使用的 Bean。
  2. 适合轻量级应用:

    • 在资源有限的环境中(如嵌入式系统),延迟加载可以显著优化性能。
    • 在开发或测试阶段,也可以通过延迟加载缩短启动时间。
  3. 按需加载:

    • 只有在确实需要使用某个 Bean 时,才会创建它的实例,避免初始化不必要的逻辑。

3. 延迟加载的实现方式

(1) 使用 @Lazy 注解

在类或方法上添加 @Lazy 注解,可以让单例 Bean 延迟加载。

示例代码:

@Component
@Lazy // 延迟加载
public class ExpensiveBean {
    public ExpensiveBean() {
        System.out.println("ExpensiveBean created!");
    }
}

测试代码:

ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println("Container initialized.");
ExpensiveBean bean = context.getBean(ExpensiveBean.class); // 此时 Bean 才会创建

运行结果:

Container initialized.
ExpensiveBean created!

解释:

  • @Lazy 生效后,ExpensiveBean 不会在容器启动时被创建。
  • 只有在调用 getBean() 时,ExpensiveBean 才会被实例化。

(2) 如果未使用 @Lazy

代码:

@Configuration
public class AppConfig {
    @Bean
    public ExpensiveBean expensiveBean() {
        return new ExpensiveBean(); // 无 @Lazy,默认预加载
    }
}

运行结果:

ExpensiveBean created!
Container initialized.

解释:

  • 默认情况下,ApplicationContext 会在启动时实例化所有单例 Bean,所以在输出 "Container initialized." 前就会创建 ExpensiveBean

(3) XML 配置方式

在 XML 文件中为 Bean 配置延迟加载:

<bean id="expensiveBean" class="com.example.ExpensiveBean" lazy-init="true"/>

(4) 在 @Configuration 中使用

对于使用 Java 配置的项目,可以在配置类中的 @Bean 方法上添加 @Lazy

@Configuration
public class AppConfig {
    @Bean
    @Lazy
    public ExpensiveBean expensiveBean() {
        return new ExpensiveBean();
    }
}

4. 延迟加载的默认行为

(1) BeanFactory 的默认行为
  • BeanFactory 是一个轻量级容器,默认使用延迟加载策略
  • 它不会在容器启动时实例化任何 Bean,而是等到调用 getBean() 方法时才实例化。
(2) ApplicationContext 的默认行为
  • ApplicationContext 是 Spring 容器的常用实现,默认会在启动时预加载所有单例(singleton) Bean
  • 例外情况:
    • 如果使用 @Lazy 注解或 XML 中的 lazy-init="true",单例 Bean 会延迟加载。
    • 非单例(prototype Scope)的 Bean 本身默认是延迟加载的。

5. 延迟加载与非延迟加载的对比

行为延迟加载非延迟加载
实例化时机调用 getBean() 时实例化容器启动时实例化
适用范围需要优化启动时间或资源消耗的场景高性能服务器或需要预加载依赖的场景
容器类型BeanFactory 默认延迟加载ApplicationContext 默认非延迟加载
预加载的 Bean无(除非显式调用)单例 Bean 默认全部实例化
性能表现启动速度快,可能会导致首次调用延迟启动时占用更多内存,运行时性能更高

6. 示例场景

  1. 资源密集型对象的加载:

    • 如果某个 Bean 的创建非常耗时(例如连接外部服务),使用延迟加载可以避免容器启动时的性能瓶颈。
  2. 开发与测试阶段:

    • 在开发和测试中,延迟加载可以缩短容器的启动时间,提升开发效率。
  3. 条件性加载:

    • 某些 Bean 只有在特定条件下才会被使用,延迟加载可以避免不必要的资源消耗。

7. 总结

  • 延迟加载的本质: Bean 只有在第一次使用时才会被实例化。
  • 优点: 减少容器启动时的资源消耗,适合轻量级或资源受限的场景。
  • 默认行为: BeanFactory 默认延迟加载,而 ApplicationContext 默认预加载单例 Bean。
  • 实现方式: 使用 @Lazy 注解或 XML 配置轻松启用延迟加载。

通过灵活地使用延迟加载,可以显著优化应用程序的启动时间和资源利用率,特别是在复杂项目或资源密集型应用中。


http://www.kler.cn/a/515811.html

相关文章:

  • 使用 Python 获取 1688 商品快递费用 API 接口的示例代码解析
  • 【项目初始化】自定义异常处理
  • C#性能优化技巧:利用Lazy<T>实现集合元素的延迟加载
  • XCode-Color-Fixer 常见问题解决方案
  • 【HarmonyOS NEXT】华为分享-碰一碰开发分享
  • “大模型横扫千军”背后的大数据挖掘--浅谈MapReduce
  • 【HeadFirst系列之HeadFirst设计模式】第3天之观察者模式
  • 激光雷达和相机早期融合
  • 利用现有模型处理面部视频获取特征向量(1)
  • # [Unity基础] 游戏物体与组件的关系
  • 【IEEE Fellow 主讲报告| EI检索稳定】第五届机器学习与智能系统工程国际学术会议(MLISE 2025)
  • Nginx 与后端服务的集成配置
  • 文本文件打印类库(C#)
  • The Surprising Effectiveness of Test-Time Training for Abstract Reasoning
  • 【设计模式-行为型】状态模式
  • React 中hooks之useInsertionEffect用法总结
  • 99.11 金融难点通俗解释:净资产收益率(ROE)VS投资资本回报率(ROIC)VS总资产收益率(ROA)
  • 【算法笔记】力扣热题100(LeetCode hot-100)438. 找到字符串中所有字母异位词 滑动窗口
  • 安卓程序作为web服务端的技术实现:AndServer 实现登录权限拦截
  • js为table列宽度添加拖拽调整
  • 原生toFixed的bug
  • 多版本并发控制:MVCC的作用和基本原理
  • javaweb之HTML
  • 【spring】集成JWT实现登录验证
  • Grafana系列之面板接入Prometheus Alertmanager
  • C#树图显示目录下所有文件以及文件大小