为何Spring推荐使用构造器注入而不是Field注入

前言

咱们都知道在 Spring Bean 的注入方式通常分为三种:一、构造器注入 二、Setter注入 三、基于注解的 @Autowired 自动装配(Field 注入)java

在以往的项目开发过程当中,咱们大多会使用方便灵活的 @Autowired 自动装配的方式来管理依赖,可是 Spring 官方却不推荐这么作

spring

Inspection info: Spring Team recommends: “Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies”.缓存

从上述信息中咱们能够得知,Spring 团队建议咱们使用构造注入的方式管理咱们的依赖,对强制依赖使用断言,那么为何不建议使用自动装配呢app

对比构造注入和Field注入

我么能够先来对比 Field 注入和 构造器注入的区别函数

Field 注入

// Field注入
public class AClass(){
    
    @Autowired`在这里插入代码片`
    private BClass BClass;
}

优势

  • 代码少,简洁明了
  • 新增依赖十分方便,不须要修改原有代码
  • 注入简单,只须要使用 @Autowired 注解或者 @Resource 注解

缺点

  • 容易出现空指针异常,Field 注入容许构建对象实例的时候依赖的示例对象为空,这就致使了空指针异常没法尽早的暴露出来
  • 对单元测试不友好,若是使用 Field 注入,那么进行单元测试就须要初始化整个Spring 环境,将全部 Bean 实例化
  • 会出现循环依赖的隐患
  • 容易破坏单一职责原则

构造器注入

// 构造器注入
public class AClass(){
    // 用 final 修饰,听从依赖不可变原则
    private final BClass bClass;
    
   	public AClass(BClass bClass){
        this.bClass = bClass;
    }
}

优势

  • 解决了依赖循环的问题(spring 的三层缓存机制)
  • 强依赖处理,在编译阶段就能暴露出问题
  • 方便单元测试
  • 能够明确的指出依赖关系

缺点

  • 代码冗余,阅读不友好

使用 Lombok 解决构造器注入代码冗余问题

针对构造器注入致使代码过于繁重的问题,咱们能够经过 lombok 插件来解决这个问题,使用lombok 的 @RequiredArgsConstructor注解生成一个包含全部常量的构造器单元测试

@RequiredArgsConstructor为每一个须要特殊处理的字段生成一个带有1个参数的构造函数。全部未初始化的final字段都将得到一个参数,以及任何标记为@NonNull且未在声明位置初始化的字段。对于那些用@NonNull标记的字段,还将生成显式null检查。若是用于标记为@NonNull的字段的任何参数包含null,则构造函数将抛出NullPointerException。参数的顺序与字段在类中出现的顺序相匹配测试

@Service
@RequiredArgsConstructor
public class LogServiceImpl implements LogService {

    private final LogRepository logRepository;
    private final LogErrorMapper logErrorMapper;
}

// 实际效果等同于

@Service
public class LogServiceImpl implements LogService {

    private final LogRepository logRepository;
    private final LogErrorMapper logErrorMapper;
    
    public LogServiceImpl(final LogRepository logRepository, final LogErrorMapper logErrorMapper) {
        this.logRepository = logRepository;
        this.logErrorMapper = logErrorMapper;
    }
}
相关文章
相关标签/搜索