SpringBoot字段注入

结城 SpringBoot 12 次阅读 1125 字 发布于 2026-05-04 预计阅读时间: 5 分钟


注:如果追求最简洁的方式,可以直接在需要注入的项目上使用注解@RequiredArgsConstructor

使用此注解只需要引用不可变私有变量,例如:

private final JwtTokenUserInterceptor jwtTokenUserInterceptor;

构造器注入

public class WebMvcConfiguration implements WebMvcConfigurer {

    private final JwtTokenUserInterceptor jwtTokenUserInterceptor;

    // 使用构造器注入
    @Autowired
    public WebMvcConfiguration(JwtTokenUserInterceptor jwtTokenUserInterceptor) {
        this.jwtTokenUserInterceptor = jwtTokenUserInterceptor;
    }
}

setter注入

public class WebMvcConfiguration implements WebMvcConfigurer {

    private JwtTokenUserInterceptor jwtTokenUserInterceptor;

    // 使用Setter注入
    @Autowired
    public void setJwtTokenUserInterceptor(JwtTokenUserInterceptor jwtTokenUserInterceptor) {
        this.jwtTokenUserInterceptor = jwtTokenUserInterceptor;
    }
}

不建议使用字段注入(Field Injection)主要有以下几个原因:

1. 可测试性问题 (Testability):

  • 依赖隐藏: 字段注入将依赖关系隐藏在类内部。在单元测试中,你需要使用反射或者其他技巧来设置这些依赖,这使得测试变得更加复杂和脆弱。
  • 难以 Mock: 因为依赖是直接注入到字段中,所以很难在测试中 Mock 或者替换这些依赖。 你需要使用 Mocking 框架的反射机制,这使得测试代码更加难以理解和维护。
  • 构造函数注入更清晰: 构造函数注入明确地声明了类的依赖关系,使得测试更加容易。你可以直接在构造函数中传入 Mock 对象。

2. 违反了依赖倒置原则 (Dependency Inversion Principle):

  • 类与 IoC 容器耦合: 字段注入使得类与 IoC 容器(如 Spring)紧密耦合。 类依赖于 IoC 容器来注入依赖,而不是依赖于抽象。
  • 构造函数注入更符合 DIP: 构造函数注入允许你将依赖作为参数传递给构造函数,这使得类更加独立,并且更容易在不同的环境中使用。

3. 不可变性问题 (Immutability):

  • 字段注入破坏了类的不可变性: 如果一个类是不可变的,那么它的所有字段都应该在构造函数中初始化,并且不能被修改。 字段注入允许在对象创建之后修改字段,这破坏了类的不可变性。
  • 构造函数注入保证不可变性: 构造函数注入可以确保所有依赖都在对象创建时被初始化,并且不能被修改,从而保证了类的不可变性。

4. 隐藏了类的真实依赖:

  • 难以理解类的依赖关系: 通过查看类的代码,你很难知道类有哪些依赖。 你需要查看 IoC 容器的配置才能了解类的依赖关系。
  • 构造函数注入更清晰: 构造函数注入明确地声明了类的依赖关系,使得代码更容易理解和维护。

5. 潜在的运行时异常:

  • NullPointerException 风险: 如果 IoC 容器没有正确地注入依赖,那么字段可能会为 null​,导致 NullPointerException
  • 构造函数注入可以避免 NPE: 构造函数注入可以确保所有依赖都被正确地注入,从而避免 NullPointerException

6. 代码可读性问题:

  • 代码不够清晰: 字段注入使得代码不够清晰,因为你需要在字段上添加 @Autowired 注解,而不是在构造函数中明确地声明依赖。
  • 构造函数注入更易读: 构造函数注入使得代码更易读,因为你可以直接在构造函数中看到类的依赖关系。

示例:

字段注入 (不推荐):

@Component
public class MyService {

    @Autowired
    private MyRepository myRepository;

    public void doSomething() {
        // 使用 myRepository
        myRepository.getData();
    }
}

构造函数注入 (推荐):

@Component
public class MyService {

    private final MyRepository myRepository;

    @Autowired // 可以省略,从 Spring 4.3 开始,如果类只有一个构造函数,@Autowired 可以省略
    public MyService(MyRepository myRepository) {
        this.myRepository = myRepository;
    }

    public void doSomething() {
        // 使用 myRepository
        myRepository.getData();
    }
}

总结:

虽然字段注入在代码编写上可能更简洁,但它在可测试性、依赖关系管理、不可变性和代码可读性方面存在诸多问题。 因此,最佳实践是使用构造函数注入,它能够更好地表达类的依赖关系,提高代码的可测试性和可维护性。

其他注入方式:

除了字段注入和构造函数注入,还有 Setter 注入。 Setter 注入通常用于可选依赖,即某些依赖不是必须的。 但是,如果依赖是必须的,仍然建议使用构造函数注入。

总而言之,尽量避免使用字段注入,优先选择构造函数注入。

给时光以生命,给岁月以文明
最后更新于 2026-06-15