Spring 中的 Setter DI 与构造函数 DI?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7779509/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 04:41:59  来源:igfitidea点击:

Setter DI vs. Constructor DI in Spring?

springdependency-injection

提问by M Sach

Spring has two two types of DI: setter DI and construction DI.

Spring有两种DI:setter DI和construction DI。

Constructor-based DI fixes the order in which the dependencies need to be injected. Setter based DI does not offer this.

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

Setter-based DI helps us to inject the dependency only when it is required, as opposed to requiring it at construction time.

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

I do not see any other significant differences, as both types of Spring DI provide the same features - both setter and constructor DI inject the dependency when the code starts up. Granted, constructor DI will do it through the constructor while setter DI will do it through a setter right after constructing the object, but it does not make any difference for the developer in terms of performance, etc. Both also offer means to specify the order of dependency injection as well.

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

I'm looking for a scenario where one provides a distinct advantage over the other or where one type is completely unusable.

我正在寻找一种场景,其中一种类型比另一种类型具有明显优势,或者一种类型完全无法使用。

回答by Tomasz Nurkiewicz

When it comes to Spring specific pros and cons:

当涉及到 Spring 的特定优点和缺点时:

  • Constructor injection (from the definition) does not allow you to create circular dependencies between beans. This limitation is actually an advantage of constructor injection - Spring can resolve circular dependencies when setter injection is used without you even noticing.

  • On the other hand if you use constructor injection CGLIB is not able to create a proxy, forcing you to either use interface-based proxies or a dummy no-arg constructor. See: SPR-3150

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

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

回答by Ryan Stewart

You should be deciding based on design considerations, not tool (Spring) considerations. Unfortunately, Spring has trained us to use setter injection because when it was originally conceived, there was no such thing as an "annotation" in Java, and in XML, setter injection works and looks much better. Today, we're freed from those constraints, thus allowing it to be a design decision again. Your beans should use constructor injection for any dependencies that are required by the bean and setter injection for dependencies that are optional and have a reasonable default, more or less as OOD has been telling us from the beginning.

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

回答by Ranga Reddy

Constructor Injection:We are injecting the dependencies through Constructor.

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

Generally we can use for Mandatory dependencies.

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

If you use the Constructor injection there is one disadvantage called "Circular Dependency".

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

Circular Dependency:Assume A and B. A is dependent on B. B is dependent on A. In this constructor injection will be failed. At that time Setter injection is useful.

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

If Object state is not inconsistent it won't create Object.

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

Setter Injection:We are injecting the dependencies through Setter methods.

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

This is useful for Non-Mandatory dependencies.

这对于非强制依赖项很有用

It is possible to re injectingdependencies by using Setter Injection.It is not possiblein Constructor injection.

可以使用Setter Injection重新注入依赖项构造函数注入中不可能的

回答by damndemon

As per the content from spring.io from Spring 5 onwards

根据 spring.io 从 Spring 5 开始的内容

Since you can mix constructor-based and setter-based DI, it is a good rule of thumb to use constructors for mandatory dependencies and setter methods or configuration methods for optional dependencies. Note that use of the @Required annotation on a setter method can be used to make the property a required dependency.

The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not null. Furthermore constructor-injected components are always returned to client (calling) code in a fully initialized state. As a side note, a large number of constructor arguments is a bad code smell, implying that the class likely has too many responsibilities and should be refactored to better address proper separation of concerns.

Setter injection should primarily only be used for optional dependencies that can be assigned reasonable default values within the class. Otherwise, not-null checks must be performed everywhere the code uses the dependency. One benefit of setter injection is that setter methods make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is therefore a compelling use case for setter injection.

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

Spring 团队通常提倡构造函数注入,因为它可以将应用程序组件实现为不可变对象,并确保所需的依赖项不为空。此外,构造函数注入的组件总是以完全初始化的状态返回给客户端(调用)代码。作为旁注,大量的构造函数参数是一种糟糕的代码味道,这意味着该类可能有太多的责任,应该重构以更好地解决适当的关注点分离问题。

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

Here is the linkfor above quote

这是上面报价的链接

But, all of the injections types are available and none of them are deprecated. At a high-level you get the same functionality across all injection types.

但是,所有的注入类型都可用,并且没有一个被弃用。在高层次上,您可以在所有注入类型中获得相同的功能。

In short, choose the injection type that works best for your team and project.

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

Recommendations from the Spring team and independent blog posts will vary over time. There is no hard-fast rule.

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

If a particular injection style was not recommended by the Spring team, then they would mark it as deprecated or obsolete. That is not the case with any of the injection styles.

如果 Spring 团队不推荐特定的注入风格,那么他们会将其标记为已弃用或过时。任何注入方式都不是这种情况。

回答by Bozho

Prefer setter injection.

更喜欢 setter 注入。

Think what would be without spring (as Ryan noted). Would you pass the dependencies in constructor? If there are too many dependencies this seems wrong. On the other hand the constructor may be used to enforce the valid state of the object - require all dependencies and verify if they are non-null.

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

Proxies are another thing (As Tomasz noted) - you will need a dummy constructor which defeats the whole idea.

代理是另一回事(正如 Tomasz 所指出的)-您将需要一个虚拟构造函数来破坏整个想法。

There is a 3rd option btw - field injection. I tend to be using that, although it is not such a good design decision, because it saves an extra setter, but if this is used outside of spring I will have to add the setter.

顺便说一句,还有第三个选项 - 场注入。我倾向于使用它,虽然这不是一个很好的设计决定,因为它节省了一个额外的 setter,但是如果在 spring 之外使用它,我将不得不添加 setter。

回答by Vishnu Dahatonde

My 2 cents. Assume a classA with 10 fields, with few injected dependencies. Now if you need entire classA with all fields then you can go for constructor injection. But if you need only one of the injected fieldto use in that class you can use setter injection.

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

This way,

这边走,

  1. You will not create new object each time.
  2. You do not need to worry about circular dependencyissue(BeanCurrentlyInCreationException).
  3. You will not have to create other fields for class A so you have much more flexible code
  1. 您不会每次都创建新对象。
  2. 您无需担心循环依赖问题(BeanCurrentlyInCreationException)。
  3. 您不必为 A 类创建其他字段,因此您拥有更灵活的代码

回答by VdeX

Since you can mix both,
Constructor DI- and Setter-based DI,
it is a good rule of thumb to use constructor arguments for mandatory dependencies and setters for optional dependencies.

由于您可以混合使用基于
构造函数 DI基于 Setter 的 DI
因此使用构造函数参数来表示强制依赖项和使用 setter 来表示可选依赖项是一个很好的经验法则。


Notethat the use of a @Required annotation on a setter can be used to make setters required dependencies.


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

回答by user3016087

no, even Constructor Injection happen , injection is still working, but just limited initialize , setter injection is optional and flexible. but it may generally for the parameter class , a spring bean with other spring beans

不,即使发生了构造函数注入,注入仍然有效,但只是有限的初始化,setter 注入是可选且灵活的。但是一般来说可能对于参数类,一个spring bean和其他spring beans