有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

spring中的java内部字段注入工作以及为什么不建议使用它

我不想知道这个领域的许多文章背后的确切原因,但我不想了解以下内容:

->;不应该使用它,因为当您进行单元测试时,您依赖于弹簧 在字段注入的情况下实例化类的容器

->;在字段注入的情况下不能使用“final”关键字,这意味着您不能使字段不可变

->;它在内部使用反射

我想知道@Autowired在内部是如何工作的,它是如何使用反射的,我试图理解上述所有观点背后的确切原因,当我们编写以下代码时,幕后会发生什么:

@Component
public class B {

    @Autowired
    private A a1;

}

我已经读过关于堆栈溢出的类似问题,但是我找不到确切的解释


共 (1) 个答案

  1. # 1 楼答案

    Spring有一个Bean后处理器的概念

    当spring构建一个bean时,它应用注册的bean后处理器来帮助“初始化”bean

    因此,有org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor处理自动布线

    基本上,它适用于新创建的对象。Spring(通过使用反射)反思bean的字段。具有@Autowired的字段是这个bean后处理器处理的主题。它在应用程序上下文中找到要注入的候选对象,并实际注入值

    现在有了这些信息,可以理解为什么最终字段不能自动连接。撇开spring不谈,在纯Java中,final字段必须在声明(final int i = 123)期间或在类的构造函数中直接实例化。但是自动关联发生在构造函数之后,因此不可能自动关联最终字段

    至于单元测试,必须从测试中以某种方式配置私有属性。但是,由于它们是封装的(是的,在本例中,spring在使用上打破了封装),因此不可能为包含字段注入的类编写一个好的测试。这就是切换到构造函数注入的原因

    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类进行测试:

    
    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
       }
    }