Spring:如何避免将构造函数注入与自动装配字段结合使用
Spring :how to avoid combining constructor injection with autowired fields
避免构造函数和字段注入的最佳替代方法是什么?
据我了解,不建议使用字段注入,构造函数是可行的方法。
(http://olivergierke.de/2013/11/why-field-injection-is-evil/)
请在下面找到我的场景,其中 class A 在 @Configuration bean 中创建,新 B() 作为构造函数参数。
但是 class A 也需要其他 bean 来操作,例如 C/D/E,后者又具有自己的自动装配依赖项。对如何在此处应用最佳推荐方法感到困惑。
有什么建议,请告诉我。
@Configuration
class Config
{
@Bean
public A create_A(){
A = new A(new B());
}
}
class A {
B b;
@Autowired
C c;
@Autowired
D d;
@Autowired
E e;
A(B b) {
this. b= b;
}
}
class C{
@Autowired
Y y;
}
您的示例有点难以理解,因为它缺少上下文。
总体而言:字段注入在存储库、服务或控制器等 Singelton 组件上很糟糕。
不知何故,你的例子有点难以理解,一个对我有用的模式:
- 使应通过 C'tor 注入的字段成为最终字段
- 用相应的Spring 构造型(@Component、@Service...)注释类
所以你必须处理这些字段,甚至编译器会告诉你是否出现问题...
@Bernd 确实回答了这个问题,但我想包含一些代码以使其更清楚
@Component
class B{
// what ever it is
}
@Component
class A {
private final B b;
private final C c;
private final D d;
private final E e;
@Autowired
A(B b, C c, D d, E e) {
this.b= b;
this.c = c;
this.d = d;
this.e = e;
}
}
@Component
class Y{
// what ever it is
}
@Component
class C{
private final Y y;
@Autowired
C(Y y){
this.y = y;
}
总的来说,@Autowired
注解出现在Spring 2.5中,后来在Spring 3.0中他们引入了“Java DSL”进行配置,方式配置 @Configuration
注释和 @Bean
注释方法。
如果您像 class A 示例中那样使用 @Configuration
,那么您实际上不必使用 @Autowired
。如果您通过 @Configuration
.
管理所有内容,您也不需要像 @Component
这样的注释
因此,假设您怀疑如何在不自动装配的情况下将 class 注入 B
或 C
到 class A
中,假设 class A
是通过 @Configuration
定义的,您可以执行以下操作:
@AllArgsConstructor // I've used lombok - it will create a constructor with B and C for you, but you can define the constructor in java as well
public class A {
private final B b;
private final C c;
...
}
@Configuration
public class MyConfiguration {
@Bean
public A a(B b, C c) {
return new A(b,c);
}
@Bean
public B b() {
return new B();
}
@Bean
public C c() {
return new C();
}
}
另一种方法是在 @Configuration
:
中使用显式方法调用
@Configuration
public class MyConfiguration {
@Bean
public A a() { // note, as opposed to the previous example, no parameters here
return new A(b(),c()); // note the explicit calls
}
@Bean
public B b() {
return new B();
}
@Bean
public C c() {
return new C();
}
}
但是如果 B
and/or C
在不同的 @Configuration
文件中或通过 @Component
注释定义[=38],此方法将不起作用=]
请注意,class A
没有任何自动装配字段,所有内容都是通过构造函数注入的。基本上 class A
现在根本没有任何 spring 相关的注释。
现在,如果您不使用 B
和 C
的配置,例如,您仍然可以将 @Component
放在它们上面,这仍然有效,因为 Spring“收集”有关应创建哪些 bean 的信息,并且它有多种资源来“获取”此类信息:通过 class 扫描 class 用 @Component
注释的 es,通过配置中定义的 @Bean
-s,等等。
即使您不管理 class A
构造函数注入仍然有效:
@Component
@AllArgsConstructor // if there is only one constructor in the class, spring will use it for autowiring automatically, so no need to put @Autowired even on the constructor for recent spring versions
class A {
private final B b;
private final C c;
}
@Component
class B {
}
@Component
class C {
}
避免构造函数和字段注入的最佳替代方法是什么?
据我了解,不建议使用字段注入,构造函数是可行的方法。 (http://olivergierke.de/2013/11/why-field-injection-is-evil/)
请在下面找到我的场景,其中 class A 在 @Configuration bean 中创建,新 B() 作为构造函数参数。
但是 class A 也需要其他 bean 来操作,例如 C/D/E,后者又具有自己的自动装配依赖项。对如何在此处应用最佳推荐方法感到困惑。
有什么建议,请告诉我。
@Configuration
class Config
{
@Bean
public A create_A(){
A = new A(new B());
}
}
class A {
B b;
@Autowired
C c;
@Autowired
D d;
@Autowired
E e;
A(B b) {
this. b= b;
}
}
class C{
@Autowired
Y y;
}
您的示例有点难以理解,因为它缺少上下文。
总体而言:字段注入在存储库、服务或控制器等 Singelton 组件上很糟糕。
不知何故,你的例子有点难以理解,一个对我有用的模式:
- 使应通过 C'tor 注入的字段成为最终字段
- 用相应的Spring 构造型(@Component、@Service...)注释类
所以你必须处理这些字段,甚至编译器会告诉你是否出现问题...
@Bernd 确实回答了这个问题,但我想包含一些代码以使其更清楚
@Component
class B{
// what ever it is
}
@Component
class A {
private final B b;
private final C c;
private final D d;
private final E e;
@Autowired
A(B b, C c, D d, E e) {
this.b= b;
this.c = c;
this.d = d;
this.e = e;
}
}
@Component
class Y{
// what ever it is
}
@Component
class C{
private final Y y;
@Autowired
C(Y y){
this.y = y;
}
总的来说,@Autowired
注解出现在Spring 2.5中,后来在Spring 3.0中他们引入了“Java DSL”进行配置,方式配置 @Configuration
注释和 @Bean
注释方法。
如果您像 class A 示例中那样使用 @Configuration
,那么您实际上不必使用 @Autowired
。如果您通过 @Configuration
.
@Component
这样的注释
因此,假设您怀疑如何在不自动装配的情况下将 class 注入 B
或 C
到 class A
中,假设 class A
是通过 @Configuration
定义的,您可以执行以下操作:
@AllArgsConstructor // I've used lombok - it will create a constructor with B and C for you, but you can define the constructor in java as well
public class A {
private final B b;
private final C c;
...
}
@Configuration
public class MyConfiguration {
@Bean
public A a(B b, C c) {
return new A(b,c);
}
@Bean
public B b() {
return new B();
}
@Bean
public C c() {
return new C();
}
}
另一种方法是在 @Configuration
:
@Configuration
public class MyConfiguration {
@Bean
public A a() { // note, as opposed to the previous example, no parameters here
return new A(b(),c()); // note the explicit calls
}
@Bean
public B b() {
return new B();
}
@Bean
public C c() {
return new C();
}
}
但是如果 B
and/or C
在不同的 @Configuration
文件中或通过 @Component
注释定义[=38],此方法将不起作用=]
请注意,class A
没有任何自动装配字段,所有内容都是通过构造函数注入的。基本上 class A
现在根本没有任何 spring 相关的注释。
现在,如果您不使用 B
和 C
的配置,例如,您仍然可以将 @Component
放在它们上面,这仍然有效,因为 Spring“收集”有关应创建哪些 bean 的信息,并且它有多种资源来“获取”此类信息:通过 class 扫描 class 用 @Component
注释的 es,通过配置中定义的 @Bean
-s,等等。
即使您不管理 class A
构造函数注入仍然有效:
@Component
@AllArgsConstructor // if there is only one constructor in the class, spring will use it for autowiring automatically, so no need to put @Autowired even on the constructor for recent spring versions
class A {
private final B b;
private final C c;
}
@Component
class B {
}
@Component
class C {
}