Bootstrap

Spring 依赖注入02

依赖注入(Dependency Injection,DI)

1. 核心概念

是面向对象编程中的一种设计模式,它主要用于降低组件之间的耦合度,促进代码的可测试性和可维护性。在依赖注入中,对象的依赖关系不是在内部创建,而是由外部容器(比如 Spring 框架)在对象创建时将依赖对象注入进来。

  1. 依赖:一个对象依赖于另一个对象,如果它需要使用另一个对象的服务或者资源来完成自身的功能。例如,一个订单服务可能依赖于一个支付服务来完成支付功能。

  2. 注入:指的是将一个对象的依赖关系传递给另一个对象的过程。依赖注入有三种主要的实现方式:

2. 依赖注入的方式

  1. 构造函数注入(Constructor Injection):依赖通过对象的构造函数传入。
  2. 设值注入(Setter Injection):依赖通过对象的设值方法(setter 方法)传入。
  3. 接口注入(Interface Injection):依赖通过特定的接口方法传入。
  4. 控制反转(Inversion of Control,IoC):依赖注入通常与控制反转紧密相关。控制反转是一种设计原则,指的是将对象的创建、管理和关联的控制权从应用程序代码中反转到外部容器(比如 Spring 容器)中。依赖注入是实现控制反转的一种方式。

3. 构造函数注入

示例

public class UserService {

    private final UserRepository userRepository;

    // 构造函数注入
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    // 其他业务方法
    public void saveUser(User user) {
        userRepository.save(user);
    }

    // 可选的设值注入方法
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

3.1 构造函数注入的优点包括:

  1. 明确性:通过构造函数明确地声明对象需要哪些依赖,提高了代码的可读性可理解性。、
  2. 不可变性:一旦对象被创建并注入了依赖,其依赖关系通常是不可变的,避免了在对象生命周期中的不必要变动。
  3. 线程安全:对象在创建时一次性注入所有依赖,避免了多线程环境下可能导致的并发问题。

4. 设值注入

设值注入(Setter Injection)是依赖注入(DI)的一种形式,它通过对象的公共设值方法(setter 方法)来注入依赖。在使用设值注入时,依赖关系不是通过对象的构造函数传入,而是在对象创建后,通过调用特定的设值方法来设置依赖。

public class UserService {

    private UserRepository userRepository;

    // 设值注入方法
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    // 其他业务方法
    public void saveUser(User user) {
        userRepository.save(user);
    }
}

4.1 设值注入的特点和优点

  1. 灵活性:与构造函数注入相比,设值注入允许在对象创建后动态地改变对象的依赖关系,因为依赖的设置是通过公共的 setter 方法完成的。
  2. 可选性:设值注入可以让某些依赖是可选的,即可以为某个依赖设置一个默认值,如果外部未提供,则使用默认值。
  3. 易于理解和维护:设值注入可以使对象的依赖关系更加明确,每个依赖可以有对应的设值方法,提高了代码的可读性和可维护性。

4.2 使用设值注入的注意事项

  1. 可选性和默认值:设值注入可以为某些依赖设置默认值,当外部未提供依赖时可以使用这些默认值。
  2. 顺序依赖:如果对象的某些依赖需要按顺序设置,设值注入可以更灵活地处理这种情况,因为可以根据具体的业务需求在合适的时间设置依赖。
  3. 不变性:设值注入使得对象在创建后可以动态地改变依赖关系,这在某些场景下可能带来不必要的复杂性和隐患,因此需要谨慎设计和使用。

5. 接口注入

接口注入(Interface Injection)是依赖注入(DI)的一种形式,它通过实现特定接口来实现依赖的注入。相较于常见的构造函数注入和设值注入,接口注入在现代框架和实践中较少使用,因为它具有一些局限性和复杂性,不如其他方式那样直观和灵活。

public interface DependencyInjector {
    void injectDependency(Object dependentObject);
}
public class MyDependencyInjector implements DependencyInjector {

    private MyDependency dependency;

    // 实现接口的注入方法
    @Override
    public void injectDependency(Object dependentObject) {
        if (dependentObject instanceof DependentClass) {
            ((DependentClass) dependentObject).setDependency(dependency);
        }
    }

    // 设置依赖对象的方法
    public void setDependency(MyDependency dependency) {
        this.dependency = dependency;
    }
}

5.1 接口注入的基本概念:

  1. 依赖注入方式:接口注入是通过实现特定接口的方式来注入依赖,该接口通常定义一个方法用于接收依赖对象。
  2. 接口定义:依赖注入的接口通常包括一个或多个方法,用于在对象创建后将依赖对象传递给实现类。
  3. 实现类:实现该接口的类需要提供方法的具体实现,以便接收依赖对象,并在适当的时机将其注入到对象中。

5.2 使用接口注入的注意事项:

  1. 复杂性和局限性:相较于构造函数注入和设值注入,接口注入需要定义接口和实现类,并且实现类需要显式地调用注入方法。这增加了代码的复杂性和依赖的耦合度。
  2. 可测试性:接口注入可能会影响代码的可测试性,因为依赖关系的设置通常需要在对象创建后进行,这可能会导致测试代码的编写和管理变得更加复杂。
  3. 现代框架实践:现代的依赖注入框架(如 Spring、Guice 等)通常更倾向于使用构造函数注入和设值注入,因为它们提供了更好的灵活性和清晰度。
;