@Autowired 或 private final

@Autowired or private final

我的问题很简单。哪种方法更有效?

方法一:

 @Autowired
 private CustomerRepository customerRepo;

方法二:

private final CustomerRepository custormerRepo;
 
public StudentService(CustomerRepository customerRepo) {
         this.customerRepo = customerRepo;
}

正如我所见,method2 中的 DI 更新了。但是我想问你我应该用哪一个?

在您的主要代码中,您应该使用方法 2,因为不推荐使用字段注入(方法 1)。 (原因见here

在你的测试代码中,使用方法一就可以了。

使用构造函数注入,Spring也推荐

TL;DR: 方法 2 更加灵活。

方法一是字段注入的例子,方法二是构造注入的例子。

字段注入有一些构造函数注入避免的缺点。以下是构造函数注入的一些优点:

不变性:

你不能这样做很简单Java:

@Autowired
private final CustomerRepository customerRepo;

// No constructor that sets "customerRepo".

因此,Spring 提供构造函数注入:

private final CustomerRepository customerRepo;

@Autowired
public StudentService(final CustomerRepository customerRepo) {
  this.customerRepo = customerRepo;
}

不变性有时是首选。一个原因是它有助于 thread-safety.

就我个人而言,我遵循规则,“如果它是最终的,它应该是最终的。”

测试:

您不需要反射来设置依赖项。是的,许多模拟框架会为您处理这个问题,但是通过构造函数注入,您可以选择在构造函数上调用 new

恶心NullPointerExceptions:

一个对象是通过调用它的构造函数来创建的,对吧?我们通常希望我们的参数在传入时为 non-null。通过构造函数注入,Spring IoC container 确保构造函数中传递的所有参数在传递给构造函数之前可用。

除了其他答案所说的不变性之外,构造函数注入的另一个好处是可以避免字段未初始化的NPE。使用自动装配,从测试中,您将创建 class 然后必须记住设置该字段。使用构造函数注入,你不能不初始化字段。这在 Kotlin 中更为突出,其中自动装配的字段被声明为 lateinit var 并且如果在初始化之前使用则抛出运行时异常。但是可以将构造函数参数声明为非空类型,这甚至会阻止您显式传递空值。

我建议你提出更好的建议。通过使用 Lombok 库的 @RequiredArgConstructor,您可以避免样板代码。如果您想知道为什么 @Autowired 不被推荐,因为当您想在您的应用程序中编写单元测试时会出现问题,如果您使用 @Autowired.