Setter DI与Spring中的Constructor DI?

时间:2011-10-15 17:42:58

标签: spring dependency-injection

Spring有两种类型的DI:setter DI和构造DI。

基于构造函数的DI修复了需要注入依赖项的顺序。基于Setter的DI不提供此功能。

基于Setter的DI帮助我们仅在需要时注入依赖关系,而不是在构造时需要它。

我没有看到任何其他显着差异,因为两种类型的Spring DI都提供相同的功能 - setter和构造函数DI在代码启动时注入依赖关系。当然,构造函数DI将通过构造函数执行,而setter DI将在构造对象后立即通过setter执行它,但它在性能等方面对开发人员没有任何影响。两者都提供了指定顺序的方法依赖注入也是如此。

我正在寻找一个场景,其中一个提供明显的优势,或者一个类型完全无法使用。

9 个答案:

答案 0 :(得分:24)

说到Spring特定的利弊:

  • 构造函数注入(来自定义)不允许您在bean之间创建循环依赖关系。这个限制实际上是构造函数注入的一个优点 - 当使用setter注入时,Spring可以解决循环依赖关系而你甚至没有注意到。

  • 另一方面,如果使用构造函数注入CGLIB无法创建代理,则强制您使用基于接口的代理或虚拟无参数构造函数。请参阅:SPR-3150

答案 1 :(得分:16)

您应该根据设计考虑而不是工具(Spring)考虑做出决定。不幸的是,Spring已经训练我们使用setter注入,因为当它最初构思时,Java中没有“注释”这样的东西,而在XML中,setter注入工作并且看起来更好。今天,我们摆脱了这些限制,从而使它再次成为一个设计决策。你的bean应该对bean和setter注入所需的任何依赖项使用构造函数注入,这些依赖项是可选的,并且具有合理的默认值,或多或少,正如OOD从一开始就告诉我们的那样。

答案 2 :(得分:9)

构造函数注入:我们通过Constructor注入依赖项。

通常我们可以使用 强制依赖。

如果使用构造函数注入,则存在一个称为“循环依赖”的缺点。

循环依赖:假设A和B. A依赖于B. B依赖于A.在此构造函数中,注入将失败。那时,Setter注射很有用。

如果对象状态不一致,则不会创建对象。

Setter Injection:我们通过Setter方法注入依赖项。

这对非强制性依赖项非常有用。

使用 Setter Injection可以重新注入依赖关系。 构造函数注入

答案 3 :(得分:2)

根据Spring 5以后的spring.io中的内容

  

由于您可以混合使用基于构造函数的DI和基于setter的DI,因此,将构造函数用于强制性依赖项,将setter方法或配置方法用于可选性依赖项是一个很好的经验法则。请注意,可以在setter方法上使用@Required批注,以使该属性成为必需的依赖项。

     

Spring团队通常提倡构造函数注入,因为它使人们能够将应用程序组件实现为不可变对象,并确保所需的依赖项不为null。此外,注入构造函数的组件总是以完全初始化的状态返回到客户端(调用)代码。附带说明一下,大量的构造函数参数是一种不好的代码味道,这表明该类可能承担了太多的责任,应该对其进行重构以更好地解决关注点分离问题。

     

Setter注入主要应仅用于可在类中分配合理的默认值的可选依赖项。否则,必须在代码使用依赖项的任何地方执行非空检查。 setter注入的一个好处是,setter方法使该类的对象在以后可以重新配置或重新注入。因此,通过JMX MBean进行管理是塞特注入的引人注目的用例。

这是上面引用的link

但是,所有注入类型均可用,并且都不弃用。从总体上讲,您可以在所有注射类型上获得相同的功能。

简而言之,选择最适合您的团队和项目的注入类型。

Spring团队的建议和独立博客文章会随时间而变化。没有硬性规定。

如果Spring团队不建议使用特定的注入方式,则他们会将其标记为已弃用或过时。任何一种注入样式都不是这种情况。

答案 4 :(得分:1)

喜欢二传手注射。

想想没有春天会是什么(正如Ryan所说)。你会在构造函数中传递依赖项吗?如果有太多依赖项,这似乎是错误的。另一方面,构造函数可用于强制执行对象的有效状态 - 需要所有依赖项并验证它们是否为非null。

代理是另一回事(正如Tomasz所说) - 你需要一个虚拟构造函数来击败整个想法。

第三种选择btw - 现场注射。我倾向于使用它,虽然它不是一个好的设计决定,因为它节省了额外的设置器,但如果在春天之外使用它我将不得不添加设置器。

答案 5 :(得分:0)

既然你可以混合两种,构造函数DI - 和基于Setter的DI ,那么 使用构造函数参数作为可选依赖项的强制依赖项和setter


注意在setter上使用@Required注释可用于使setter成为必需的依赖项。

答案 6 :(得分:0)

我的2美分。 假设有10个字段的classA,其中注入的依赖项很少。 现在,如果您需要包含所有字段的整个classA,则可以进行构造函数注入。 但是,如果您只需要一个注入字段在该课程中使用,则可以使用设置注入

这样,

  1. 您不会每次都创建新对象。
  2. 您不必担心循环依赖问题(BeanCurrentlyInCreationException)。
  3. 您不必为A类创建其他字段,因此您的代码更加灵活

答案 7 :(得分:0)

这可能不是主要优势。但是让我解释一下Spring中的注入机制。

这两种方法的区别在于,使用@ Inject,@ Autowire等进行注入的方式,Spring将使用反射将一个bean注入另一个bean,并且通过构造函数的方式,我们自己按顺序使用构造函数在不使用反射的情况下由另一个bean初始化一个bean。

因此,使用构造函数的方式会提供更好的其他选择,至少我们不使用反射机制,因为从机器方面来说,反射是一项昂贵的操作。

附言请考虑,构造DI的正确用法是当您使用带参数的构造函数手动创建bean时,即使您可以在没有任何构造函数的情况下使用构造函数进行创建。

答案 8 :(得分:-1)

不,甚至构造函数注入发生,注入仍在工作,但只是初始化有限,setter注入是可选的和灵活的。但它通常可以用于参数类,一个带有其他spring bean的spring bean