为什么要使用构造方法进行依赖注入?
Posted hanstrovsky
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么要使用构造方法进行依赖注入?相关的知识,希望对你有一定的参考价值。
一、前言
我们在使用Spring框架进行开发时,不可避免的要进行依赖注入(Dependency Injection),也就是把实例从Spring容器中取出来进行使用。Spring的依赖注入方式主要有三种,分别为Constructor、Setter和Field。有了选择的余地,令人纠结的地方就来了,这三种方式哪个更好一些呢?
二、注入方式对比
Constructor注入
private DependencyA dependencyA; @Autowired public DI(DependencyA dependencyA) { this.dependencyA = dependencyA; }
Setter注入
private DependencyB dependencyB; @Autowired public void setDependencyB(DependencyB dependencyB) { this.dependencyB = dependencyB; }
Field注入
@Autowired private DependencyC dependencyC;
三、选择哪种注入方式
对比这三种方式,Field注入显得清爽又整洁。写的时候方便快捷,读起来也很赏心悦目,看起来肯定要优先选择使用它啊。然而,这种方式是存在一些缺点的。
- 由于操作简单,代码简洁,使用者可能稍不留神注入了太多的依赖,造成该类承担了太多的责任。违背了单一职责的设计原则。至于为什么要遵从单一原则,可自行百度。
- 由于没有提供全参构造或set方法,那么使用者有可能通过默认的空参构造new出实例,使用时发生空指针异常。
- 此类不能在DI容器(测试,其他模块)之外重用,因为除了反射以外,没有其他方法可以为其提供所需的依赖关系。
- 有可能产生循环依赖报出BeanCurrentlyInCreationException,下方只是一个例子,现实中出现的情况会更难缠。
public class A { @Autowired private B b; } public class B { @Autowired private C c; } public class C { @Autowired private A a; }
Spring官方目前推荐的是构造器注入。根据官方的说法,因为它使人们能够将应用程序组件实现为不可变对象,并确保所需的依赖项不为null。此外,注入构造函数的组件总是以完全初始化的状态返回到客户端(调用)代码。
-
不可变对象:说的是可以是字段用final关键字修饰。
-
依赖不为null:因为有了自定义的构造函数,所以程序不再提供默认的空参构造,类在实例化时必须传入所有需要的参数。
-
完全初始化的状态:构造方法的作用就是初始化成员变量,在Java类加载实例化的过程中,构造方法是最后一步,所以返回来的组件都是初始化之后的状态。
总结
Field注入
优点
-
最简洁
缺点
-
便利会弱化代码结构设计
-
-
依赖不能是可变的(无法final)
-
容易出现循环依赖
-
需要使用到多个spring或者java注解
Set注入
优点
- 对循环依赖免疫
- 随着setter的添加,高度耦合的类很容易被识别出来。
缺点
- 违反开放封闭原则
- 会把循环依赖隐藏掉
- 三种方法里最模板化的方式
- 依赖不能是可变的(无法final)
Constructor注入
优点
-
依赖可以是final的
-
三种方式里最容易测试的方式
-
高耦合类随着构造参数的增长很容易被识别出来
-
其他开发平台的开发者也很熟悉
-
不需要依赖@Autowired注解
缺点
- 构造函数需要下沉到子类
以上是关于为什么要使用构造方法进行依赖注入?的主要内容,如果未能解决你的问题,请参考以下文章