【问题标题】:Spring: circular dependencies on constructor\setter injectionSpring:构造函数\setter注入的循环依赖
【发布时间】:2014-01-17 09:28:01
【问题描述】:

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

所以问题:

  1. 我可以通过setter 注入完成circular dependency 吗?
  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>
    

【问题讨论】:

  • 循环依赖可以用 setter 来解决,但这不是原因。原因是 AConstr 需要 BConstr ,反之亦然。当使用构造函数而不是设置器时,这将是可见的,但无论哪种方式,你都有一个循环依赖。

标签: java spring dependency-injection


【解决方案1】:

使用 Spring @Autowired 注入依赖有两种方式:通过 field 或通过 constructor

如果你有以下层:

  • 休息控制器
  • 服务
  • JpaRepository
  • 实体

使用以下绑定:

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

因此,2 个服务 可以相互依赖(直接或不依赖)是正常的,这就是您可以打破循环依赖的原因:

  • @Autowiredfields 上,而不是在您的一项服务中的 constructor
  • 或者只是在构造函数参数前添加@Lazy

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

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

【讨论】:

    【解决方案2】:

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

    1. 在构造函数注入的情况下,它会来到构造函数这里说AConstr,然后它会再次看到BConstr必须在执行AConstr之前注入到BConstr和尝试创建BConstr 的对象。

    2. 现在它将控制BConstr 的构造函数,然后它将找到依赖项'AConstr'。这将创建永无止境的链条。

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

    4. 所以当你打电话时

       context.getBean("aConstr");
      

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

    【讨论】:

    • 是的,但我的意思是仍然使用构造函数注入来解决这个问题。例如,通过使用 bean 的回调之一(类似于afterPropertiesSet)。有可能吗?
    • 不必要的为什么要增加代码。建议在 CircularDependency 的情况下使用 setter,我不确定我们是否可以处理 afterPropertySet,因为 afterPropertySet 在构造函数执行后被调用我不是 100% 确定那。检查一次。
    【解决方案3】:

    我知道答案有点晚了,但迟到总比没有好:

    如果你仔细阅读这篇文章你会发现很可能你的设计是错误的: http://misko.hevery.com/2008/08/01/circular-dependency-in-constructors-and-dependency-injection/

    Setter 注入只会对你隐藏它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-02
      • 2021-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多