java 初始化 bean 的最佳方法是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/210996/
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-10-29 11:26:26  来源:igfitidea点击:

What is the best way to initialize a bean?

javaspring

提问by Bob Herrmann

In spring you can initialize a bean by having the applicationContext.xml invoke a constructor, or you can set properties on the bean. What are the trade offs between the two approaches? Is it better to have a constructor (which enforces the contract of having everything it needs in one method) or is it better to have all properties (which gives you flexibility to only inject selectively for example when unit testing.)

在 spring 中,您可以通过让 applicationContext.xml 调用构造函数来初始化 bean,或者您可以在 bean 上设置属性。这两种方法之间的权衡是什么?是拥有一个构造函数更好(它强制执行在一个方法中拥有它需要的一切的合同)还是拥有所有属性更好(这使您可以灵活地仅选择性地注入,例如在单元测试时。)

What are the trade offs (between writing a bean that uses a constructor to establish it's initial state, or using properties and perhaps an afterProperties() method) ?

有什么权衡(在编写使用构造函数建立初始状态的 bean,或使用属性和 afterProperties() 方法之间)?

回答by lycono

I'm not sure there is a "best" way to initialize a bean. I think there are pros and cons to each, and depending on the situation, one or the other might be appropriate. This certainly isn't an exhaustive list, but here are some things to consider.

我不确定是否有一种“最佳”方式来初始化 bean。我认为各有利弊,视情况而定,其中之一可能是合适的。这当然不是一个详尽的清单,但这里有一些需要考虑的事情。

Using a constructor allows you to have an immutable bean. Immutable objects are good if you can fit them in your design. They don't require copying, serialized access or other special handling between threads. If you have setters, your object isn't immutable. Using a constructor also ensures the object is properly initialized. After the constructor finishes, the object is valid. If your object requiresthe use of setters to initialize it, it's possible to have an invalid object.

使用构造函数可以让您拥有一个不可变的 bean。如果您可以将不可变对象放入您的设计中,它们就很好。它们不需要在线程之间进行复制、序列化访问或其他特殊处理。如果你有 setter,你的对象不是不可变的。使用构造函数还可以确保对象被正确初始化。构造函数完成后,对象有效。如果您的对象需要使用 setter 来初始化它,则可能有一个无效的对象。

On the other hand, using constructors often leads to a telescoping problem. Often times you'll need many different constructors, most of which will be a superset of another constructor. Often times these are for convenience. For instance:

另一方面,使用构造函数通常会导致伸缩问题。很多时候你需要很多不同的构造函数,其中大部分是另一个构造函数的超集。很多时候这些都是为了方便。例如:

public class Person {
  public Person(String name) { ... }
  public Person(String name, String phone) { ... }
  public Person(String name, String phone, String email) { ... }
}

One alternative to this that I very much like is the so called "enhanced" builder pattern presented by Josh Bloch at JavaOne. You can see this in his book "Effective Java, Second Edition". If you look at the way the pattern is used, it will also solve your "afterProperties" method issue. The builder pattern will guarantee the object is correctly initialized.

我非常喜欢的一种替代方法是 Josh Bloch 在 JavaOne 提出的所谓“增强型”构建器模式。您可以在他的“Effective Java, Second Edition”一书中看到这一点。如果您查看模式的使用方式,它也会解决您的“afterProperties”方法问题。构建器模式将保证对象被正确初始化。

Here is an additional blog post discussing the pattern: http://www.screaming-penguin.com/node/7598

这是讨论该模式的其他博客文章:http: //www.screaming-penguin.com/node/7598

I'm not sure this fits into your spring requirement, but in general, I'm a big fan of builder.

我不确定这是否符合您的弹簧要求,但总的来说,我是 builder 的忠实粉丝。

回答by Dónal

IMO the major advantage of constructor injection is that it is compatible with immutability. However, if a class has more than about 3 dependencies, this requires providing a constructor which takes a large number of parameters, which is unwieldy.

IMO 构造函数注入的主要优点是它与不变性兼容。但是,如果一个类有大约 3 个以上的依赖项,则需要提供一个带有大量参数的构造函数,这很笨拙。

When using setter-injection, I prefer to use the @PostConstructannotation to identify the initialization method. This involves looser coupling to the Spring framework than the afterProperties()method you mention (actually, I think it's afterPropertiesSet()). Another option is the init method attribute of the <bean>element.

在使用 setter-injection 时,我更喜欢使用@PostConstruct注解来标识初始化方法。与afterProperties()您提到的方法相比,这涉及到与 Spring 框架的松散耦合(实际上,我认为是afterPropertiesSet())。另一种选择是<bean>元素的 init 方法属性。

回答by Jaap Coomans

I don't know the version you are currently using, but if it is Spring 2.5 you could also consider using the @Autowired annotation for certain cases. This of coarse only works for references to other beans and not for Strings etc. as in lycony's example.

我不知道您当前使用的版本,但如果是 Spring 2.5,您也可以考虑在某些情况下使用 @Autowired 批注。这种粗只适用于对其他 bean 的引用,而不适用于字符串等,如 lycony 的示例。

It saves you the burden of creating setters and/or constructors and a lot of configuration. A little Example:

它为您节省了创建 setter 和/或构造函数以及大量配置的负担。一个小例子:

public class MyPersonBean {
  @Autowired
  private PersonManager personManager;

  public void doSomething() {
    this.personManager.doSomething();
  }
}

And in your config file:

在你的配置文件中:

<context:annotation-config/>

Autowiring is done by type, so if you have a bean of the type PersonManager, it will inject it in the annotated field. In case you have more beans of that type you can use the @Qualifier annotation to tell them apart...

自动装配是按类型完成的,所以如果你有一个 PersonManager 类型的 bean,它将把它注入到带注释的字段中。如果您有更多该类型的 bean,您可以使用 @Qualifier 注释来区分它们...

You can find more info about autowiring in the Spring Reference Documentation

您可以在Spring 参考文档中找到有关自动装配的更多信息

I started using @Autowired in combination with component-scanning in my previous project and I must say that I got rid of more than 90% of my Spring configuration files.

我在之前的项目中开始将@Autowired 与组件扫描结合使用,我必须说我摆脱了超过 90% 的 Spring 配置文件。

回答by MetroidFan2002

The tradeoffs:

权衡:

Constructor: Benefits: Can be very simple, esp. with three or less properties to initialize. One-shot, no/minimal extra configuration to worry about.

构造函数:优点:可以非常简单,尤其是。具有三个或更少要初始化的属性。一次性,无需/最少需要担心的额外配置。

Drawbacks: Multiple constructors must be created for several situations Constructors aren't inherited, so classes must call super() and provide duplicate constructors to allow the previous behavior.

缺点:必须为多种情况创建多个构造函数 构造函数不是继承的,因此类必须调用 super() 并提供重复的构造函数以允许之前的行为。

Setters: Benefits: Children inherit setters, so properties can be easily overridden to influence behavior after construction. Multiple properties may be specified in a unified fashion without looking up different method signatures (JavaBeans conventions)

Setter:优点:子级继承 setter,因此属性可以很容易地被覆盖以影响构造后的行为。可以以统一的方式指定多个属性,而无需查找不同的方法签名(JavaBeans 约定)

Drawbacks: Every setter must be invoked explicitly for every property. Leads to some classes having large numbers of properties explicitly set.

缺点:必须为每个属性显式调用每个 setter。导致某些类显式设置了大量属性。

回答by kukudas

You can also use @Resourceto autowire instead of @Autowired, this works kinda like autowire byName so you don't have to worry if there are more beans with the same type (ofc you can also handle that with @Qualifier, but I would only recommend that to describe a characteristic of a bean). It really depends on your use case which way will be the best so you have to evaluate it for your situation and decide after.

你也可以使用@Resourceto autowire 而不是@Autowired,这有点像 autowire byName 这样你就不必担心是否有更多相同类型的 bean(ofc 你也可以用 来处理@Qualifier,但我只建议用它来描述一个豆的特征)。这实际上取决于您的用例,哪种方式最好,因此您必须根据您的情况对其进行评估,然后再决定。