关于spring依赖注入的方式以及优缺点
作者:xiegongmiao
一.依赖注入的三种方式
1.通过构造器注入。(spring4.3之后,推荐使用)
2.通过setter注入。(spring4.3之前,推荐使用)
3通过filed注入。
二.三种方式的代码示例:
Constructor注入
private AlarmContactService alarmContactService; private final AlarmService alarmService; private final SysUserService sysUserService; @Autowired public AlarmContactController(AlarmContactService alarmContactService, AlarmService alarmService, SysUserService sysUserService) { this.alarmContactService = alarmContactService; this.alarmService = alarmService; this.sysUserService = sysUserService; }
Setter注入
private AlarmContactService alarmContactService; private AlarmService alarmService; private SysUserService sysUserService; @Autowired public void setAlarmContactService(AlarmContactService alarmContactService) { this.alarmContactService = alarmContactService; } @Autowired public void setAlarmService(AlarmService alarmService) { this.alarmService = alarmService; } @Autowired public void setSysUserService(SysUserService sysUserService) { this.sysUserService = sysUserService; }
Field注入
@Autowired private AlarmContactService alarmContactService; @Autowired private AlarmService alarmService; @Autowired private SysUserService sysUserService;
三.3种方式的各优点和缺点
三种方式的优点分析
1.基于构造器注入,会固定依赖注入的顺序,不允许我们创建的bean对象之间存在循环依赖关系,这样Spring能解决循环依赖的问题。
2.基于setter注入,只有对象是需要被注入的时候,才会注入依赖,而不是在初始化的时候就注入。
3.在成员变量上写上注解来注入,这种方式,精短,可读性高,不需要多余的代码,也方便维护。
三种方式的缺点分析
1.使用构造器注入的缺点是,当我们构造器需要注入的对象比较多时,会显得我们的构造器,冗余,不美观,可读性差,也不易维护。
2.当我们选择setter方法来注入的时候,我们不能将对象设为final的;
3.当我们在field变量上来实现注入的时候
a.这样不符合JavaBean的规范,而且很有可能引起空指针;
b.同时也不能将对象标为final的;
c.类与DI容器高度耦合,我们不能在外部使用它;
d.类不通过反射不能被实例化(例如单元测试中),你需要用DI容器去实例化它,这更像集成测试;
来自Spring官方文档的建议
在Spring 3.x 中,Spring团队建议我们使用setter来注入:
而在Spring 4.x 中,Spring团队不再建议我们使用setter来注入,改为了constructor:
Spring团队通常建议使用构造器来注入,因为它允许一个应用程序组件实现为不可变对象,并确保所需的依赖项不是空。此外构造器注入组件总是返回一个完全初始化状态的client客户端(调用)。附注,大量的构造函数参数是一个糟糕的代码习惯,看起来也很坏,这意味着类可能有太多的责任,应该被重构,以更好地解决适当的关注点分离。
三.解释下什么是循环依赖
1. 循环依赖是什么?
Bean A 依赖 B,Bean B 依赖 A这种情况下出现循环依赖。
Bean A → Bean B → Bean A 或者 Bean A → Bean B → BeanC → Bean A
2. 循环依赖会产生什么结果?
当Spring正在加载所有Bean时,Spring尝试以能正常创建Bean的顺序去创建Bean。
例如,有如下依赖:
Bean A → Bean B → Bean C
Spring先创建beanC,接着创建bean B(将C注入B中),最后创建bean A(将B注入A中)。
假如,有如下循环依赖:
Bean A → Bean B → Bean C → BeanD → Bean A
但当存在循环依赖时,Spring将无法决定先创建哪个bean。这种情况下,Spring将产生异常BeanCurrentlyInCreationException。
Spring 4.3 的新特征:
在Spring 4.3 以后,如果我们的类中只有单个构造函数,那么Spring就会实现一个隐式的自动注入:
就是我去掉了构造器上的@Autowired注解,经测试后发现,程序能正常运行。alarmContactService,alarmService,sysUserService的依赖也被成功注入了。
private AlarmContactService alarmContactService; private final AlarmService alarmService; private final SysUserService sysUserService; public AlarmContactController(AlarmContactService alarmContactService, AlarmService alarmService, SysUserService sysUserService) { this.alarmContactService = alarmContactService; this.alarmService = alarmService; this.sysUserService = sysUserService; }
使用构造注入允许加入final,这也表示以后不能再被更改了。
到此这篇关于关于spring依赖注入的方式以及优缺点的文章就介绍到这了,更多相关spring依赖注入内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!