Spring依赖注入DI之三种依赖注入类型详解
作者:黄泥川水猴子
Spring依赖注入
字段注入
首先,我们可以使用字段注入。想要在一个类中通过字段的形式注入某个对象,可以采用这样的方式:
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注入类似于选择性注入。
- 允许在类构造完成后重新注入。
缺点: 暂无
到此这篇关于Spring依赖注入DI之三种依赖注入类型详解的文章就介绍到这了,更多相关Spring依赖注入内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!