不加 @Lazy 一定会发生循环依赖,启动失败吗?
不加 Lazy 一定会发生循环依赖启动失败吗绝对不是。不加Lazy注解并不代表一定会发生循环依赖或启动失败。Lazy只是解决特定问题的“药”而不是所有项目的“饭”。为了让你彻底放心我们需要把**“循环依赖”和“启动失败”**这两个概念拆开来看。 情况一根本没有循环依赖最常见如果你的代码设计是清晰的树状或链状结构比如Controller - Service - DaoA - B - C在这种情况下完全不需要Lazy。Spring 会按照顺序依次创建 C然后 B最后 A。一切运行完美没有任何报错。✅ 情况二有循环依赖但 Spring 能自动搞定单例 字段注入这是 Spring 最强大的地方。如果你有以下场景A 和 B 互相依赖(A注入B,B注入A)都是单例(Scope(singleton)默认就是)使用字段注入(Autowired在属性上) 或 Setter 注入结论不加Lazy也能正常启动原理Spring 的三级缓存机制非常强大。它允许先创建一个“半成品”的 A还没填属性放入三级缓存然后去创建 BB 需要 A 时Spring 从三级缓存里把那个“半成品 A”拿出来给 B 用。等 B 创建好了再回头把完整的 B 塞给 A。注意这种情况下虽然不加Lazy能跑通但如果你的项目升级到了 Spring Boot 2.6默认配置可能会禁止这种循环引用这时你就需要在配置文件里开启spring.main.allow-circular-referencestrue或者还是得加Lazy。❌ 情况三不加 Lazy 必死无疑必须加的场景只有在以下几种“硬骨头”场景下不加Lazy才会导致启动报错1. 构造器注入导致的循环依赖ServicepublicclassA{privatefinalBb;// 构造器注入A 创建时必须要有 BpublicA(Bb){this.bb;}}ServicepublicclassB{privatefinalAa;// 构造器注入B 创建时必须要有 ApublicB(Aa){this.aa;}}结果这是一个死锁。A 等 B 出生B 等 A 出生。Spring 的三级缓存也救不了因为对象还没实例化没法放入缓存。解法必须在其中一个构造参数上加Lazy。2. 多例Prototype作用域的循环依赖ServiceScope(prototype)// 多例publicclassA{AutowiredBb;}ServiceScope(prototype)// 多例publicclassB{AutowiredAa;}结果Spring 的三级缓存只支持单例 Bean 的循环依赖。对于多例Spring 每次都要创建新对象无法缓存“半成品”所以直接报错。解法加Lazy。3. 自己注入自己自调用ServicepublicclassUserService{AutowiredprivateUserServiceuserService;// 自己注入自己}结果这本质上也是一种循环依赖。如果不加LazySpring 会陷入无限递归创建中。解法必须加Lazy。 总结对照表场景是否构成循环依赖不加Lazy会怎样备注普通单向依赖(A-B)否✅正常启动绝大多数项目的常态单例 字段注入(A-B)是✅通常能启动Spring 三级缓存自动解决(但在 Boot 2.6 需配置允许)构造器注入(A-B)是❌启动报错必须加Lazy破局多例 Bean(A-B)是❌启动报错必须加Lazy破局自注入(A-A)是❌启动报错必须加Lazy破局所以只有当你确实遇到了上述几种“死锁”情况或者你想优化启动性能延迟加载重量级 Bean时才需要考虑Lazy。