spring 字段注入的内部工作原理以及为什么不推荐使用
Internal working of field injection in spring and why is it not recommended to use
正如标题所暗示的,我想知道字段注入在 spring 中是如何工作的,我阅读了很多这方面的文章,并了解了一些类似下面的内容,但不明白背后的确切原因它:
-> 不应该使用它,因为当您进行单元测试时,您依赖于 spring
在字段注入的情况下实例化 class 的容器。
-> 在字段注入的情况下不能使用“final”关键字,这意味着不能使字段不可变。
-> 内部使用反射
我想知道@Autowired 在内部究竟是如何工作的,它是如何使用反射的,我想了解上述所有要点背后的确切原因,当我们编写以下代码时幕后发生了什么:
@Component
public class B {
@Autowired
private A a1;
}
我已经阅读过有关此主题的堆栈溢出的类似问题,但找不到我正在寻找的确切解释。
Spring 有 Bean Post 处理器的概念。
当 spring 构建一个 bean 时,它会应用已注册的 bean post 处理器来帮助“初始化”该 bean。
所以,有 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
处理自动装配。
基本上它适用于新创建的对象。 Spring 内省 bean 的字段(通过使用反射)。具有 @Autowired
的字段是使用此 bean post 处理器处理的主题。它在应用程序上下文中找到注入的候选者并实际注入值。
现在有了这些信息,就可以理解为什么最终字段不能自动装配了。别管 spring,在纯 Java 中,final 字段必须在声明 (final int i = 123
) 期间或在 class 的构造函数中直接实例化。但是自动装配发生在构造函数之后,所以不可能自动装配最终字段。
至于单元测试,私有属性必须以某种方式从测试中配置。但是由于它们是封装的(是的,spring 在这种情况下使用时会破坏封装),不可能为包含字段注入的 class 编写好的测试。这就是切换到构造函数注入的原因。
public class FieldInjection {
@Autowired
private A a;
}
VS.
public class ConstructorInjection {
private final A a;
// this can be generated by lombok, you don't have to put @Autowired on constructor in the case of single constructor, spring will use it to create a bean
public ConstructorInjection(A a) {
this.a = a;
}
}
现在无法对 FieldInjection class 进行测试:
public class FieldInjectionTest {
@Test
void test() {
FieldInjection underTest = new FieldInjection();
how do you know that you should instantiate A a. ????
}
}
然而,在构造函数注入的情况下,这是一项微不足道的任务:
public class ConstructorInjectionTest {
@Test
void test() {
A a = mock(A.class);
ConstructorInjection underTest = new ConstructorInjection(a);
// the dependencies must be supplied in the constructor
// otherwise its impossible to create an object under test
}
}
正如标题所暗示的,我想知道字段注入在 spring 中是如何工作的,我阅读了很多这方面的文章,并了解了一些类似下面的内容,但不明白背后的确切原因它:
-> 不应该使用它,因为当您进行单元测试时,您依赖于 spring 在字段注入的情况下实例化 class 的容器。
-> 在字段注入的情况下不能使用“final”关键字,这意味着不能使字段不可变。
-> 内部使用反射
我想知道@Autowired 在内部究竟是如何工作的,它是如何使用反射的,我想了解上述所有要点背后的确切原因,当我们编写以下代码时幕后发生了什么:
@Component
public class B {
@Autowired
private A a1;
}
我已经阅读过有关此主题的堆栈溢出的类似问题,但找不到我正在寻找的确切解释。
Spring 有 Bean Post 处理器的概念。
当 spring 构建一个 bean 时,它会应用已注册的 bean post 处理器来帮助“初始化”该 bean。
所以,有 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
处理自动装配。
基本上它适用于新创建的对象。 Spring 内省 bean 的字段(通过使用反射)。具有 @Autowired
的字段是使用此 bean post 处理器处理的主题。它在应用程序上下文中找到注入的候选者并实际注入值。
现在有了这些信息,就可以理解为什么最终字段不能自动装配了。别管 spring,在纯 Java 中,final 字段必须在声明 (final int i = 123
) 期间或在 class 的构造函数中直接实例化。但是自动装配发生在构造函数之后,所以不可能自动装配最终字段。
至于单元测试,私有属性必须以某种方式从测试中配置。但是由于它们是封装的(是的,spring 在这种情况下使用时会破坏封装),不可能为包含字段注入的 class 编写好的测试。这就是切换到构造函数注入的原因。
public class FieldInjection {
@Autowired
private A a;
}
VS.
public class ConstructorInjection {
private final A a;
// this can be generated by lombok, you don't have to put @Autowired on constructor in the case of single constructor, spring will use it to create a bean
public ConstructorInjection(A a) {
this.a = a;
}
}
现在无法对 FieldInjection class 进行测试:
public class FieldInjectionTest {
@Test
void test() {
FieldInjection underTest = new FieldInjection();
how do you know that you should instantiate A a. ????
}
}
然而,在构造函数注入的情况下,这是一项微不足道的任务:
public class ConstructorInjectionTest {
@Test
void test() {
A a = mock(A.class);
ConstructorInjection underTest = new ConstructorInjection(a);
// the dependencies must be supplied in the constructor
// otherwise its impossible to create an object under test
}
}