解释为什么构造函数注入比其他选项更好

在Pro Spring 3书的第4章 - 春季介绍IOC和DI - 第59页,在“Setter Injection vs. Constructor Injection”部分中,有一段说

包含Spring,提供了一种机制,用于确保在使用Setter注入时定义所有依赖项,但是通过使用构造函数注入,您可以以与容器无关的方式断言依赖项的要求”

你能用例子解释一下吗?


答案 1

将必需的依赖项作为构造函数参数的类只有在提供该参数时才能实例化(您应该有一个 guard 子句以确保该参数不为 null)(或在 Kotlin 中使用不可为 null 的类型)。因此,无论您是否使用Spring,构造函数都会强制执行依赖项要求,使其与容器无关。

如果使用 setter 注入,则可能会或可能不会调用 setter,因此可能永远不会为实例提供其依赖项。强制调用 setter 的唯一方法是使用 or ,这是特定于 Spring 的,因此不是与容器无关的。@Required@Autowired

因此,要使代码独立于 Spring,请使用构造函数参数进行注入。这适用于测试;您将更容易在正常的单元测试中实例化和测试类,而无需配置应用程序上下文或设置集成测试带来的复杂性。

更新:Spring 4.3 将在单构造函数方案中执行隐式注入,使您的代码更加独立于 Spring,因为可能根本不需要注释。@Autowired


答案 2

(...)通过使用构造函数注入,可以以与容器无关的方式断言依赖项的要求

这意味着您可以对所有注入的字段强制实施要求,而无需使用任何特定于容器的解决方案


Setter Injection 示例

与设置器喷射需要特殊的弹簧注释。@Required

@Required

将方法(通常是 JavaBean setter 方法)标记为“必需”:也就是说,必须将 setter 方法配置为使用值注入依赖项。

用法

import org.springframework.beans.factory.annotation.Required;

import javax.inject.Inject;
import javax.inject.Named;

@Named
public class Foo {

    private Bar bar;

    @Inject
    @Required
    public void setBar(Bar bar) {
        this.bar = bar;
    }
}

构造函数注入示例

所有必填字段都在构造函数纯 Java 解决方案中定义。

用法

import javax.inject.Inject;
import javax.inject.Named;

@Named
public class Foo {

    private Bar bar;

    @Inject
    public Foo(Bar bar) {
        this.bar = bar;
    }

}

单元测试

这在单元测试中特别有用。这样的测试应该非常简单,并且不理解注释,它们通常不需要Spring来运行简单的单元测试。当使用构造函数时,用于测试的此类的设置要容易得多,无需分析测试类的实现方式。@Required


推荐