@Lazy注解能解决循环依赖吗?
1 个回答
不必太张扬,是花自然香。丁隐#### **能,但仅限于构造器注入的循环依赖。** **Spring 的三级缓存机制** 可以解决 **"setter 注入(@Autowired)"** 方式下的循环依赖,但对于 **"构造器注入"**,因为 Bean 在实例化时必须完全满足依赖关系,Spring 无法提前暴露 Bean,因此 **三级缓存无法解决构造器注入的循环依赖**。 在这种情况下,`@Lazy` 可以**延迟加载某个 Bean**,避免在构造器注入时立即实例化,从而**打破循环依赖**。 ### **1. 为什么 `@Lazy` 能解决构造器循环依赖?** `@Lazy` 使得 **依赖的 Bean 不会立即被创建,而是等到真正使用时再实例化**。 这样,Spring 在创建 A 时,不需要立即创建 B,从而避免了循环依赖。 **示例:构造器注入导致的循环依赖** ```java @Component public class A { private final B b; @Autowired public A(B b) { this.b = b; } } @Component public class B { private final A a; @Autowired public B(A a) { this.a = a; } } ``` **上面的代码会导致 `BeanCurrentlyInCreationException`,因为 A 和 B 互相依赖,构造器注入要求 Spring 在创建 A 时必须先创建 B,但 B 也依赖 A,导致死循环。** ### **2. 使用 `@Lazy` 解决构造器循环依赖** **只需要在其中一个构造器的参数上加 `@Lazy`,让 Spring 在真正使用时再创建该 Bean。** ```java @Component public class A { private final B b; @Autowired public A(@Lazy B b) { // B 的实例化被延迟 this.b = b; } } @Component public class B { private final A a; @Autowired public B(A a) { this.a = a; } } ``` **执行流程** 1. Spring 先创建 `A`,但 `B` 是 `@Lazy` 的,因此 `B` **不会立即被实例化**,而是**代理**(`CGLIB` 代理)。 2. Spring 创建 `B` 时,`A` 已经存在,**不会再触发循环依赖**。 3. 当 `A` 真的调用 `B` 时,Spring 再真正实例化 `B`。 ### **3. `@Lazy` 在字段、类级别的用法** #### **(1)@Lazy 用在类上** ```java @Component @Lazy public class LazyBean { public LazyBean() { System.out.println("LazyBean 初始化..."); } } ``` **作用**:`LazyBean` 只有在**第一次被真正使用时**才会被创建,而不是在 Spring 启动时创建。 #### **(2)@Lazy 用在依赖注入字段上** ```java @Component public class SomeClass { @Autowired @Lazy private LazyBean lazyBean; public void doSomething() { lazyBean.toString(); // 这里才会真正初始化 LazyBean } } ``` **作用**:即使 `SomeClass` 在 Spring 容器启动时被创建,`LazyBean` 依然不会立即被实例化,只有在 `doSomething()` 里调用 `lazyBean` 时,才会创建 `LazyBean`。 ### **4. `@Lazy` 解决循环依赖的局限** 1. **只能解决构造器注入的循环依赖**,不能替代三级缓存机制解决 `@Autowired` 方式的循环依赖。 2. **可能会导致懒加载的 Bean 初始化时出现延迟问题**,如果 `LazyBean` 依赖复杂,可能会影响系统性能。 3. **不适合所有情况**,最好还是优化 Bean 之间的依赖关系,而不是依赖 `@Lazy` 解决循环依赖。 ### **5. 结论** ✅ **`@Lazy` 能解决 "构造器注入" 方式的循环依赖,因为它延迟实例化 Bean,避免立即创建依赖项。** ✅ **但它不适用于 `@Autowired` 方式的循环依赖,Spring 已经通过三级缓存解决了这个问题。** ✅ **不建议过度使用 `@Lazy`,最佳做法是优化 Bean 设计,减少不必要的循环依赖。**编辑于 2025-05-20 11:49 •IP属地 北京举报评论收藏
公众号进入网站体验更佳

