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

发布于 2024-12-10 02:22:05 字数 415 浏览 0 评论 0原文

Spring有两种类型的DI(依赖注入):setter DI和construction DI。

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

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

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

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

Spring has two two types of DI (Dependency Injection): setter DI and construction DI.

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

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

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.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

土豪 2024-12-17 02:22:05

当谈到 Spring 的具体优缺点时:

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

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

When it comes to Spring specific pros and cons:

  • 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

相对绾红妆 2024-12-17 02:22:05

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

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.

远山浅 2024-12-17 02:22:05

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

一般来说,我们可以使用强制依赖。

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

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

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

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

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

可以通过使用Setter 注入来重新注入依赖项。这是不可能< /strong> 在构造函数注入中。

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.

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

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

This is useful for Non-Mandatory dependencies.

It is possible to re injecting dependencies by using Setter Injection. It is not possible in Constructor injection.

烟酒忠诚 2024-12-17 02:22:05

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

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

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

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

这是 上述引用的链接

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

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

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

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

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

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.

Here is the link for 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.

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.

故人的歌 2024-12-17 02:22:05

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

这样,

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

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 field to use in that class you can use setter injection.

This way,

  1. You will not create new object each time.
  2. You do not need to worry about circular dependency issue(BeanCurrentlyInCreationException).
  3. You will not have to create other fields for class A so you have much more flexible code
画骨成沙 2024-12-17 02:22:05

更喜欢设置器注入。

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

代理是另一回事(正如 Tomasz 指出的)——你将需要一个虚拟的构造函数,它会破坏整个想法。

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

Prefer setter injection.

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.

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.

稚气少女 2024-12-17 02:22:05

由于您可以混合使用
构造函数 DI基于 Setter 的 DI
这是使用的一个很好的经验法则强制依赖项的构造函数参数和可选依赖项的设置器

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

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.

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

土豪 2024-12-17 02:22:05

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

The meaning of the difference these two approaches is that with the way of injection using @Inject, @Autowire and so on, Spring will inject one bean into another using reflection, and with the way of the constructor, we ourselves use the constructor in order to initialize one bean by another bean without using reflection.

Therefore, the way with constructor better other option, at least that we don't use reflection-mechanism because reflection is an expensive operation from the machine-side.

P.S. Please consider, that correct use of construction DI it's when you manually create bean through constructor with params, even though you can you create using constructor without any of them.

Probably it's not main advantage. But let me explain mechanism of injection in Spring.

The meaning of the difference these two approaches is that with the way of injection using @Inject, @Autowire and so on, Spring will inject one bean into another using reflection, and with the way of the constructor, we ourselves use the constructor in order to initialize one bean by another bean without using reflection.

Therefore, the way with constructor better other option, at least that we don't use reflection-mechanism because reflection is an expensive operation from the machine-side.

P.S. Please consider, that correct use of construction DI it's when you manually create bean through constructor with params, even though you can you create using constructor without any of them.

何止钟意 2024-12-17 02:22:05

不,即使发生构造函数注入,注入仍然有效,但只是有限的初始化,setter注入是可选且灵活的。但通常可以为参数类,一个spring bean和其他spring bean

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文