Spring:对构造函数\setter 注入的循环依赖

VB_*_*VB_ 5 java spring dependency-injection

我读过circular dependencies是由setter注射引起的。所以我试着自己检查一下。看来我circular dependency只能通过 constructor 注入来复制(见下面的代码)。

所以问题:

  1. 我可以circular dependency通过setter注射完成吗?
  2. circular dependencies下面的代码如何解决?

    public class AConstr {
    
      private final BConstr b;
    
      public AConstr(BConstr bConstr) {
        System.out.println("AConstructor:: constructor");
        this.b = bConstr;
      }
    }
    
    public class BConstr {
    
      private final AConstr a;
    
      public BConstr(AConstr aConstr) {
        System.out.println("BConstructor:: constructor");
        this.a = aConstr;
      }
    }
    
    <bean id="aConstr" class="pack.bean.AConstr">
       <constructor-arg ref="bConstr"/>
    </bean>
    <bean id="bConstr" class="pack.bean.BConstr">
       <constructor-arg ref="aConstr"/>
    </bean>
    
    Run Code Online (Sandbox Code Playgroud)

Ple*_*mor 5

有两种使用 Spring 注入依赖项的方法@Autowired:通过字段或通过构造函数

如果您有以下层:

  • 休息控制器
  • 服务
  • Jpa存储库
  • 实体

使用以下绑定:

  • 1 RestController仅绑定到关联的Service
  • 1 Service仅使用关联的JpaRepositories来管理关联的Entities
  • 为了与服务功能范围之外的实体进行交互,服务使用其他服务
FooController       BarController
+                   +
|                   |
+                   +
FooService<-------->BarService
+                   +
|                   |
+                   +
FooJpaRepository    BarJpaRepository
+                   +
|                   |
+                   +
FooEntity           BarEntity
Run Code Online (Sandbox Code Playgroud)

因此,两个服务可以相互依赖(直接或不直接)是正常的,这就是为什么你可以打破循环依赖:

  • 在您的服务之一中使用@Autowiredon字段而不是 on构造函数
  • 或者只是@Lazy在构造函数参数之前添加。

这是Spring的建议:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-dependency

另一方面,Service(或者直接是JpaRepository)应该通过constructor注入到RestControllers中。在这种情况下,循环依赖将是一个架构问题。


Sho*_*ate 2

请参阅循环依赖仅由构造函数注入引起。在此示例中,您可以使用 setter 而不是构造函数。

  1. 在构造函数注入的情况下,它将来到构造函数,AConstr并一次又一次地看到必须BConstr在执行之前注入,AConstr它将转到BConstr并尝试创建 的对象BConstr

  2. 现在,当它的控制权到达 的BConstr构造函数时,它将找到依赖项“AConstr”。这将创造一条永无止境的链条。

  3. 在 Setter 注入期间,为了注入一个对象,它将创建该对象。所以如果你有 setter 注入就没问题。

  4. 所以当你打电话时

     context.getBean("aConstr");
    
    Run Code Online (Sandbox Code Playgroud)

它将aConstr首先创建一个对象,然后调用 setter 注入,进一步将依赖项注入为bConstr

  • 不必要为什么要增加代码。建议在 CircularDependency 的情况下使用 setter,我不确定我们是否可以处理 afterPropertySet,因为 afterPropertySet 在构造函数执行后被调用,我对此不是 100% 确定。检查一次。 (2认同)