You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

final修饰符与@Lazy注解是否存在冲突?

关于Spring @Lazy与构造注入的懒加载问题

你的假设在未使用参数级@Lazy的场景下完全成立,但Spring其实提供了专门的机制,让构造注入(哪怕是final字段)也能实现依赖的懒加载,这是容易被忽略的细节:

核心逻辑:构造注入的默认行为

构造函数调用的本质是必须传入所有参数值,所以默认情况下,不管你给当前Bean加不加@Lazy,只要构造参数是另一个Bean,Spring都会立即初始化这个依赖Bean来完成构造——毕竟你总不能给构造函数传个"空"来初始化final字段,也没法在构造完成后再反射修改final字段(这会破坏Java的语义)。

打破默认:参数级@Lazy+动态代理

Spring的@Lazy注解可以直接标记在构造函数的参数上,这时候Spring不会直接初始化依赖的真实Bean,而是生成一个动态代理对象传入构造函数。这个代理会在你第一次实际调用依赖的方法/访问属性时,才触发真实Bean的初始化。

举个实际代码例子:

@Component
public class MyService {
    // final字段完全不影响
    private final LazyDao lazyDao;

    // 给构造参数添加@Lazy
    public MyService(@Lazy LazyDao lazyDao) {
        this.lazyDao = lazyDao;
        // 此时lazyDao是代理对象,LazyDao的构造方法还没执行
        System.out.println("MyService initialized");
    }

    public void queryData() {
        // 第一次调用lazyDao的方法时,才会初始化真实的LazyDao实例
        lazyDao.fetch();
    }
}

@Component
public class LazyDao {
    public LazyDao() {
        System.out.println("LazyDao initialized");
    }

    public void fetch() {}
}

启动应用时只会打印MyService initialized,直到调用queryData()方法,才会打印LazyDao initialized。

关于无final字段的情况

如果字段没有final修饰,但没给构造参数加@Lazy,构造调用时依然会立即初始化依赖Bean——因为构造函数必须拿到参数值才能创建实例,Spring不会在构造完成后再反射注入这个字段(这不是构造注入的语义)。只有用参数级@Lazy,才能实现构造注入场景下的依赖懒加载,和字段是否final无关。

总结

  • 你的原始假设(构造注入默认无法懒加载依赖,不管字段是否final)是对的,但这是未使用参数级@Lazy的情况;
  • Spring通过参数级@Lazy+动态代理的机制,让构造注入(包括final字段)也能实现依赖的懒加载,这是关键的解决方案。

内容的提问来源于stack exchange,提问作者Poltix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 07:23:22