如何正确进行依赖注入(在Spring中)?

19 浏览
0 Comments

如何正确进行依赖注入(在Spring中)?

我对使用Spring将对象注入类的方式有些疑惑。在我的项目中,我通常会使用以下代码:

@Resource // 或 @Autowired 或 @Inject
private PersonRepository personRepository;

然后在方法中正常使用它:

personRepository.save(p);

另外,我在Spring的示例中发现了通过构造函数注入的方式:

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

所以这两种方式都是正确的吗?还是每种方式都有自己的特点和用法?

0
0 Comments

问题的出现的原因:

- Java beans规范基于使用mutators(即setter方法)来简化反射,导致过多的工具和框架都基于这种访问方式。

- 对于服务、DAO和其他单例场景,只应该使用构造函数注入,因为mutators违反了“只有朋友才能看到你的私密部分”的原则。

解决方法:

- 对于依赖注入,应该使用构造函数注入,而不是mutators。

- 方法(包括构造函数)对于真正的面向对象编程来说是不必要的。

以下是整理后的文章:

面向对象编程中,构造函数被认为是创建对象的更好方式。然而,Java beans规范却建立在使用mutators(即setter方法)来简化反射的基础上。这导致许多工具和框架都以这种访问方式为依据。对于服务、DAO和其他单例场景,只应该使用构造函数注入,因为mutators违反了“只有朋友才能看到你的私密部分”的原则。

对于依赖注入,应该使用构造函数注入,而不是mutators。这是因为方法(包括构造函数)对于真正的面向对象编程来说是不必要的。构造函数注入可以提高代码的可测试性和可维护性,同时避免了对对象内部状态的直接访问。通过构造函数注入,我们可以明确地声明一个对象所需的依赖,并将其注入到对象中。这使得对象的创建和使用更加清晰和可控。

以下是使用Spring框架进行依赖注入的示例代码:

public class UserService {
    private final UserRepository userRepository;
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    // ...
}
public class UserRepository {
    // ...
}
public class Main {
    public static void main(String[] args) {
        UserRepository userRepository = new UserRepository();
        UserService userService = new UserService(userRepository);
        // ...
    }
}

在上面的示例中,UserService通过构造函数接收UserRepository的实例,并将其保存在私有字段中。这样,UserService就可以使用UserRepository来执行相应的操作。通过构造函数注入,我们不再依赖mutators来设置UserService的依赖。这使得代码更加简洁和可测试。

对于依赖注入,在Spring等框架中,我们应该使用构造函数注入来替代mutators。构造函数注入可以提高代码的可测试性和可维护性,同时遵循面向对象编程的原则。通过明确地声明对象所需的依赖,并将其注入到对象中,我们可以使代码更加清晰和可控。

0
0 Comments

依赖注入(DI)是一种设计模式,它的目的是通过外部注入对象的依赖来提高代码的可测试性、可维护性和可扩展性。在Spring框架中,有多种方式可以实现依赖注入,其中最常用的是构造函数注入。

构造函数注入是一种最佳的依赖注入方式,这不仅是因为Spring或任何依赖注入容器,而是因为面向对象的类设计原则。一个类型应该被设计成只能通过它来创建处于有效状态的实例。为了实现这一点,该类型的所有必需依赖关系都需要作为构造函数参数。这意味着这些依赖关系可以进行空值检查,并分配给final字段以促进不可变性。此外,在使用代码时,对于该实例的调用者(或创建者)来说,立即明确它必须提供哪些依赖关系(通过查看API文档或在IDE中使用代码完成)。

这些都是使用字段注入无法实现的。从外部看不到依赖关系,你需要一些黑魔法来注入依赖关系,除非你盲目地相信容器,否则你无法确定它们不是空值。

最后但同样重要的一点实际上是,使用字段注入时,向类添加大量依赖关系会更加轻松,这本身就是一个设计问题。使用构造函数,这将更加痛苦,这是一个好事,因为它告诉你一些关于类设计的信息:该类具有太多的责任。不需要首先计算它的指标,当你尝试扩展它时,你会感觉到。

关于容器的争论通常是说这只是学术上的废话,因为你可以依赖于容器。以下是我的看法:

只因为存在容器,并不意味着你必须放弃所有基本的面向对象设计原则,对吗?即使有了止汗剂,你还是会洗澡,对吗?

即使是为容器设计的类型,也会手动使用:在单元测试中。如果你不写单元测试...那就是另一个话题了。

附加构造函数的所谓冗余(“我可以通过一行字段注入来实现相同的功能!” - “不,你不能。你实际上通过编写一行代码来得到东西。”)可以通过像Lombok这样的工具来减轻。使用Spring和Lombok的构造函数注入组件如下所示:

class MyComponent implements MyComponentInterface {
  private final MyDependency dependency;
  …
}

Lombok将负责为每个final字段生成一个带有参数的构造函数,并在分配之前检查给定的参数是否为null。因此,您既可以获得字段注入的简洁性,又可以获得构造函数注入的设计优势。

总之,最近我参与了一个与非Java人士的讨论,他们对使用术语“注入”来表示构造函数DI感到非常困惑。实际上,他们认为 - 这有很多道理 - 通过构造函数传递依赖关系根本不是注入,因为这是将对象传递给其他对象的最自然的方式(与任何注入形式形成鲜明对比)。

也许我们应该为这种风格创造一个不同的术语?依赖关系传递,也许?

资源:

- Oliver Gierke - 为什么字段注入是有害的

- Jens Schauder - 唯一正确的依赖注入方式

容器=DI容器=您用来实现DI的框架。没有人会争辩你需要一个容器,只是通常流行的容器通常允许以不同的方式注入依赖关系。我基本上认为,这不应该影响你在设计类时的方式。

依赖注入(DI)是一种设计模式,它的目的是通过外部注入对象的依赖来提高代码的可测试性、可维护性和可扩展性。在Spring框架中,有多种方式可以实现依赖注入,其中最常用的是构造函数注入。

构造函数注入是一种最佳的依赖注入方式,这不仅是因为Spring或任何依赖注入容器,而是因为面向对象的类设计原则。一个类型应该被设计成只能通过它来创建处于有效状态的实例。为了实现这一点,该类型的所有必需依赖关系都需要作为构造函数参数。这意味着这些依赖关系可以进行空值检查,并分配给final字段以促进不可变性。此外,在使用代码时,对于该实例的调用者(或创建者)来说,立即明确它必须提供哪些依赖关系(通过查看API文档或在IDE中使用代码完成)。

这些都是使用字段注入无法实现的。从外部看不到依赖关系,你需要一些黑魔法来注入依赖关系,除非你盲目地相信容器,否则你无法确定它们不是空值。

最后但同样重要的一点实际上是,使用字段注入时,向类添加大量依赖关系会更加轻松,这本身就是一个设计问题。使用构造函数,这将更加痛苦,这是一个好事,因为它告诉你一些关于类设计的信息:该类具有太多的责任。不需要首先计算它的指标,当你尝试扩展它时,你会感觉到。

关于容器的争论通常是说这只是学术上的废话,因为你可以依赖于容器。只因为存在容器,并不意味着你必须放弃所有基本的面向对象设计原则,对吗?即使有了止汗剂,你还是会洗澡,对吗?

即使是为容器设计的类型,也会手动使用:在单元测试中。如果你不写单元测试...那就是另一个话题了。

附加构造函数的所谓冗余(“我可以通过一行字段注入来实现相同的功能!” - “不,你不能。你实际上通过编写一行代码来得到东西。”)可以通过像Lombok这样的工具来减轻。使用Spring和Lombok的构造函数注入组件如下所示:

class MyComponent implements MyComponentInterface {
  private final MyDependency dependency;
  …
}

Lombok将负责为每个final字段生成一个带有参数的构造函数,并在分配之前检查给定的参数是否为null。因此,您既可以获得字段注入的简洁性,又可以获得构造函数注入的设计优势。

总之,最近我参与了一个与非Java人士的讨论,他们对使用术语“注入”来表示构造函数DI感到非常困惑。实际上,他们认为 - 这有很多道理 - 通过构造函数传递依赖关系根本不是注入,因为这是将对象传递给其他对象的最自然的方式(与任何注入形式形成鲜明对比)。

也许我们应该为这种风格创造一个不同的术语?依赖关系传递,也许?

资源:

- Oliver Gierke - 为什么字段注入是有害的

- Jens Schauder - 唯一正确的依赖注入方式

0