跳转到内容

Spring Bean懒加载

来自代码酷

Spring Bean懒加载[编辑 | 编辑源代码]

Spring Bean懒加载(Lazy Initialization)是Spring框架中控制Bean初始化时机的重要机制。默认情况下,Spring容器会在启动时立即创建所有单例Bean,而懒加载允许将某些Bean的初始化延迟到首次被请求时。

核心概念[编辑 | 编辑源代码]

立即加载 vs 懒加载[编辑 | 编辑源代码]

  • 立即加载(Eager Loading):默认模式,应用上下文启动时创建所有单例Bean
  • 懒加载(Lazy Loading):只有在第一次被依赖注入或显式调用时才初始化

数学表示[编辑 | 编辑源代码]

设Bean集合为B={b1,b2,...,bn},初始化函数为init()

  • 立即加载:bB,init(b)在容器启动时执行
  • 懒加载:bB,init(b)在首次访问时执行

配置方式[编辑 | 编辑源代码]

XML配置[编辑 | 编辑源代码]

<bean id="lazyBean" class="com.example.LazyBean" lazy-init="true"/>

注解配置[编辑 | 编辑源代码]

@Lazy
@Component
public class LazyBean { ... }

Java配置[编辑 | 编辑源代码]

@Configuration
public class AppConfig {
    @Bean
    @Lazy
    public MyBean myBean() {
        return new MyBean();
    }
}

工作原理[编辑 | 编辑源代码]

sequenceDiagram participant Client participant Container participant LazyBean Client->>Container: getBean("lazyBean") Container->>LazyBean: 首次调用时初始化 LazyBean-->>Container: 返回实例 Container-->>Client: 返回代理对象

实际案例[编辑 | 编辑源代码]

场景:大型对象延迟初始化[编辑 | 编辑源代码]

@Lazy
@Service
public class HeavyResourceService {
    private final Map<String, byte[]> cache = new HashMap<>();
    
    public HeavyResourceService() {
        System.out.println("初始化重量级资源...");
        // 模拟耗时操作
        for(int i=0; i<10000; i++) {
            cache.put("key"+i, new byte[1024]);
        }
    }
    
    public byte[] getResource(String key) {
        return cache.get(key);
    }
}

输出结果

// 应用启动时无输出
// 首次调用getResource()时输出:
初始化重量级资源...

高级主题[编辑 | 编辑源代码]

懒加载的代理机制[编辑 | 编辑源代码]

Spring使用CGLIB或JDK动态代理实现懒加载:

  • 对接口使用JDK动态代理
  • 对类使用CGLIB代理

与其他特性的交互[编辑 | 编辑源代码]

特性 交互效果
@DependsOn 强制初始化顺序
@Scope("prototype") 每次请求都创建新实例
@PostConstruct 延迟到首次使用时执行

最佳实践[编辑 | 编辑源代码]

适用场景

  • 初始化耗时的Bean
  • 不常用的功能组件
  • 存在循环依赖时作为解决方案之一

注意事项

  • 可能掩盖配置错误(直到运行时才发现)
  • 增加首次请求的响应时间
  • 不适合所有场景(如应用启动必须的Bean)

性能影响[编辑 | 编辑源代码]

使用懒加载可以:

  • 减少应用启动时间
  • 降低内存初始占用
  • 但会增加首次请求延迟

性能对比公式: Ttotal={Tstartup+Tinit(立即加载)Tstartup+Tfirst_access(懒加载)

常见问题[编辑 | 编辑源代码]

Q:懒加载Bean中的@Autowired字段何时注入?[编辑 | 编辑源代码]

A:在Bean初始化时(首次访问时)完成依赖注入

Q:如何强制初始化懒加载Bean?[编辑 | 编辑源代码]

// 方法1:显式调用
context.getBean(LazyBean.class);

// 方法2:实现SmartLifecycle
public class MyLifecycle implements SmartLifecycle {
    @Autowired
    private LazyBean lazyBean;
    
    public void start() {
        // 触发初始化
    }
}