Skip to content

介绍一下类的懒加载

约 891 字大约 3 分钟

Spring框架小红书

2025-03-14

⭐ 题目日期:

小红书 - 2024/11/11

📝 题解:

类的懒加载(Lazy Loading)详解

懒加载(Lazy Loading)是一种延迟初始化技术,其核心思想是 在需要时才创建或加载资源,避免不必要的性能开销。以下是懒加载在不同场景下的实现方式、优缺点及实际应用示例:


1. 懒加载的核心思想

  • 延迟初始化:对象的创建或数据的加载推迟到首次访问时。
  • 资源优化:减少启动时间和内存占用,提升性能。
  • 按需加载:适用于初始化成本高或使用频率低的资源。

2. 不同上下文中的懒加载实现

(1) Spring 框架中的 Bean 懒加载

  • 实现方式: 使用 @Lazy 注解标记 Bean,Spring 容器在启动时不会初始化该 Bean,而是等到首次注入或获取时再初始化。
@Configuration
public class AppConfig {
    @Bean
    @Lazy  // 懒加载
    public ExpensiveService expensiveService() {
        return new ExpensiveService();
    }
}
  • 适用场景
    • Bean 初始化耗时(如数据库连接、第三方服务初始化)。
    • Bean 可能不会被立即使用(如功能模块按需加载)。

(2) Hibernate ORM中的关联懒加载

  • 实现方式: 在实体关联字段(如 @OneToMany)上设置 fetch = FetchType.LAZY,延迟加载关联数据。
@Entity
public class Order {
    @OneToMany(fetch = FetchType.LAZY)
    private List<OrderItem> items;  // 懒加载关联的订单项
}
  • 注意事项
    • 访问懒加载字段需在 Hibernate Session 未关闭的情况下进行,否则会抛出 LazyInitializationException
    • 可通过 Fetch JoinHibernate.initialize() 主动加载。

(3) 单例模式的懒加载(线程安全)

  • 实现方式: 使用双重检查锁定(Double-Checked Locking)或静态内部类。
public class Singleton {
    private static volatile Singleton instance;
    
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

(4) Java 8 的 Supplier 延迟初始化

  • 实现方式: 利用 Supplier 接口延迟创建对象。
public class Lazy<T> {
    private Supplier<T> supplier;
    private T value;
    
    public Lazy(Supplier<T> supplier) {
        this.supplier = supplier;
    }
    
    public T get() {
        if (value == null) {
            value = supplier.get();
        }
        return value;
    }
}
// 使用示例
Lazy<ExpensiveResource> resource = new Lazy<>(ExpensiveResource::new);

3. 懒加载的优缺点

img


4. 适用场景

  • 高开销对象:如数据库连接池、缓存初始化。
  • 低频使用资源:如日志服务、辅助工具类。
  • 模块化架构:按需加载插件或功能模块。
  • 大规模数据:如分页查询、懒加载列表数据。

5. 注意事项

  • 线程安全:多线程环境下需确保懒加载代码的原子性。
  • 异常处理:捕获初始化时的异常,避免程序崩溃。
  • 资源释放:懒加载的资源需在适当时候释放(如 Spring Bean 的销毁回调)。
  • 循环依赖:在依赖注入框架中,懒加载可能掩盖循环依赖问题。

6. 示例:Spring 中的懒加载实战

配置类

@Configuration
public class LazyConfig {
    @Bean
    @Lazy
    public HeavyResource heavyResource() {
        System.out.println("Initializing HeavyResource...");
        return new HeavyResource();
    }
}

使用类

@Service
public class MyService {
    @Autowired
    private HeavyResource heavyResource;  // 首次访问时初始化
    
    public void doWork() {
        heavyResource.process();  // 此时才会创建 HeavyResource 实例
    }
}

输出结果

// 启动时无输出
// 调用 doWork() 后输出:Initializing HeavyResource...

总结

懒加载通过延迟资源初始化,优化了应用的启动性能和内存使用,尤其在处理高开销、低频访问的资源时效果显著。然而,需权衡其带来的运行时延迟和复杂度增加。在 Spring、Hibernate 等框架中,合理利用懒加载机制能显著提升系统效率。