java – 如何正确地执行依赖注入(在Spring中)?

我对使用Spring注入对象有疑问。我在我的项目中使用这种代码:

@Resource // or @Autowired even @Inject
private PersonRepository personRepository;

然后在方法上通常使用它:

personRepository.save(p);

否则我发现在Spring示例中,注入构造函数:

private final PersonRepository personRepository;

@Autowired
public PersonController(PersonRepository personRepository) {
  this.personRepository = personRepository;
}

所以都是正确的?还是每个都有其属性和用途?

tl; dr – 构造器注入是DI的最佳方法

后者是正确的,这不是因为Spring或任何依赖注入容器,而是面向对象的类设计原则。

细节

应该设计一个类型,以便只能从它创建一个处于有效状态的实例。为了实现这一点,这种类型的所有强制依赖都需要是构造函数参数。这意味着,这些依赖关系可以被空检,分配给最终的字段以促进不变性。除此之外,当使用代码时,对于该实例的调用者(或创建者),它立即显而易见的是它提供的依赖关系(通过API文档中的撇号或在IDE中使用代码完成)。

所有这一切都是不可能的现场注射。你没有看到外部的依赖,你需要一些黑魔法来注入依赖项,除非你盲目地信任容器,否则你永远不能确定它们不是空的。

实际上最后但并非最不重要的一个方面是,通过现场注入,向您的课堂添加大量依赖关系,这本身就是一个设计问题,这不算那么痛苦。随着构造函数在更早的时候变得更加痛苦,这是一件好事,因为它告诉你一些关于你的类设计:类有太多的责任。没有必要首先计算它的指标,当您尝试扩展它时,您会感觉到它。

集装箱

人们经常认为,这只是学术上的bull it,因为你可以依靠集装箱。这是我的看法:

>只是因为一个容器存在,这并不意味着你必须在板上抛出所有基本的面向对象的设计原则,是吗?你仍然洗澡,即使止汗剂存在,对吧?
>使用容器设计的均匀类型将手动使用:单元测试。如果你不写单元测试…那就是另一个话题。
>一个额外的构造函数(“我可以通过一个单一的字段注入来实现同样的事情”) – “不,你不能,你实际上从编写一行代码更多的东西”)可以是通过像Lombok这样的东西来缓解。使用Spring和Lombok注入组件的构造函数如下所示:

@Component
@RequiredArgsConstructor(onConstructor = @__(@Inject))
class MyComponent implements MyComponentInterface {

  private final @NonNull MyDependency dependency;

  …
}

Lombok将负责为每个最终字段生成一个用@Inject注释的构造函数,并在给定参数之前检查给定的参数。因此,您可以有效地获得现场注入的简洁性和构造器注入的设计优势。

结语

最近我和一些非Java的人讨论过我对使用构造函数DI的术语“注入”感到困惑的一部分。实际上,他们认为 – 有很多真相 – 通过构造函数传递依赖关系根本不是注入的,因为它是将对象交给他人的最自然的方法(与任何种类的注入形成鲜明对比)。

也许我们应该为这种风格设一个不同的术语?依赖性喂养,也许?

资源

> Oliver Gierke – Why field injection is evil
> Jens Schauder – The one correct way to do dependency injection

http://stackoverflow.com/questions/24337486/how-to-properly-do-dependency-injection-in-spring

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:java – 如何正确地执行依赖注入(在Spring中)?