Spring DI(依赖注入)之三种依赖注入类型

在这里插入图片描述

字段注入

首先,我们可以使用字段注入。想要在一个类中通过字段的形式注入某个对象,可以采用这样的方式:

public class ClientService { 
 
    @Autowired 
    private HealthRecordService healthRecordService; 
 
    public void recordUserHealthData() { 
        healthRecordService.recordUserHealthData(); 
    } 
}

可以看到,通过 @Autowired 注解,字段注入的实现方式非常简单而直接,代码的可读性也很强。事实上,字段注入是三种注入方式中最常用、也是最容易使用的一种。但它也是三种注入方式中最应该避免使用的。就像开篇说的,我们在 IDEA 中使用字段注入时会遇到“Field injection is not recommended”的提示。你知道为什么吗?原因有三点。

问题一、

字段注入的最大问题是对象的外部可见性。在前面的 ClientService 类中,我们通过定义一个私有变量 HealthRecordService 来注入该接口的实例。显然,这个实例只能在 ClientService 类中被访问,脱离了容器环境我们无法访问这个实例,来看下面这段代码:

ClientService clientService = new ClientService(); 
clientService.recordUserHealthData (); 

执行这段代码的结果就是抛出一个 NullPointerException 空指针异常,原因就在于无法在 ClientService 的外部实例化 HealthRecordService 对象。采用字段注入,类与容器的耦合度过高,我们无法脱离容器来使用目标对象。如果编写测试用例来验证 ClientService 类的正确性,那么想要使用 HealthRecordService 对象,就只能使用反射的方式,这种做法实际上是不符合 JavaBean 开发规范的,而且可能一直无法发现空指针异常的存在。

问题二、

我们无法设置需要注入的对象为 final,也无法注入那些不可变对象,final类型的变量在调用class的构造函数的这个过程当中就得初始化完成,这个是基于字段的依赖注入做不到的地方,只能使用基于构造函数的依赖注入的方式.

问题三、

字段注入的第三个问题是可能导致潜在的循环依赖,即两个类之间互相进行注入,例如下面这段示例代码:

public class ClassA { 
 
    @Autowired 
    private ClassB classB; 
} 
 
public class ClassB { 
 
    @Autowired 
    private ClassA classA; 
} 

这里的 ClassA 和 ClassB 发生了循环依赖。上述代码在 Spring 中是合法的,容器启动时并不会报任何错误,而只有在使用到具体某个 ClassA 或 ClassB 时才会报错。

问题四、

无法对注入的属性进行安全检查
在程序启动的时候无法拿到这个类,只有在真正的业务使用的时候才会拿到,若注入的是null,因为不调用将一直无法发NullPointException的存在。
或者想在属性注入的时候,增加验证措施,也无法办到。

基于以上四点,无论是 IDEA,还是 Spring 官方,都不推荐开发人员使用字段注入这种注入模式,而是推荐构造器注入。

在面试中,针对字段注入,请记住它主要的三点缺陷:不具备外部可见性、会导致循环依赖,以及无法注入不可变对象

构造器注入

@Controller
@RequestMapping("employee")
public class EmployeeController {
    
    private final EmployeeMapper employeeMapper;
    
    @Autowired
    public EmployeeController(EmployeeMapper employeeMapper) {
        this.employeeMapper = employeeMapper;
    }
}

优点:

  • 保证依赖不可变(final关键字)。
  • 保证依赖不为空(省去了我们对其检查)。
  • 保证返回客户端(调用)的代码的时候是完全初始化的状态。
  • 避免了循环依赖。
  • 提升了代码的可复用性。
  • 可以明确成员变量的注入顺序。
    缺点:
  • 当注入参数较多时,代码臃肿。

set方法注入

@Controller
@RequestMapping("employee")
public class EmployeeController {
    
    private EmployeeMapper employeeMapper;
    
    @Autowired
    public void setEmployeeMapper(EmployeeMapper employeeMapper) {
        this.employeeMapper = employeeMapper;
    }
}

优点:
相比构造器注入,set注入类似于选择性注入。
允许在类构造完成后重新注入。
缺点:
暂无

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值