初识Spring IoC

零、前言 从第一天开始学习SpringBoot,到现在已经有两年了,两年内我的搬砖能力不断增强,但理论层面仍然是零基础小白。
因此,打破瓶颈的方法,就是像学长们一样,多读书、多看理论知识,然后应用实践。
所以我开始学习Spring的两大特性之一——控制反转IoC。
在此之前,我们需要了解什么是依赖关系。
如果A的成功运行必须需要调用B,此时就可以称为B是A的依赖。
举个例子,Controller要想调用Service的方法,就必须有一个可以操作的Service对象的引用(指针),此时这个Controller就依赖这个Service。
一、常规情况下,依赖关系的对象是怎么实例化的 最传统的方式就是:直接new对象,用谁就new谁。
例如:
如果想完成一个学生管理的功能,需要StudentController(控制器)、StudentService(服务)以及StudentRepository(仓库),而学生和班级是ManyToOne,因此可能会调用KlassService(班级服务)和KlassRepository(班级仓库)
而在实现班级管理时,也是类似的依赖关系。
如图所示:
如果学生Service想查看学生信息,就要:

//实例化学生仓库 private StudentRepository studentRepository = new StudentRepository(); // 实例化班级服务和班级仓库,从而实现关联查询 private KlassService klassService = new KlassService(); private KlassRepository klassRepository = KlassRepository();

并且,如果班级Service想查看班级信息,就要:
//实例化班级仓库 private KlassRepository klassRepository = KlassRepository(); // 实例化学生服务和学生仓库,从而查看每个班级里的学生 StudentService studentService = new StudentService(); private StudentRepository studentRepository = new StudentRepository();

此外,C层调用Service时,也需要实例化它:
StudentService studentService = new StudentService();

这样一来,确实可以通过new对象实现组件间依赖关系,但问题也很明显。
局限性 从业务逻辑上看,控制器、服务、仓库,都是负责数据流的处理和传递,所以应该都是单例模式,重复的实例化这些对象除了消耗多余资源以外,更重要的是会干扰内部分变量的正常调用。
所以完全可以让全局共享同一个依赖关系的实例对象。
有人可能会说,那可以继续改进一下,只在某个特定的组件中完成它的依赖关系调用,其他的组件共享这些对象。
但由于业务逻辑的不确定性,编写时很难确定组件的生命周期,
谁来创建、何时创建、何时释放、释放时能否保证它已经不被调用了,这些都是问题。
二、控制反转(Inversion of Control) 控制反转的字面意思是:本来维护对象的工作由开发者完成,所谓反转,就是把这个过程交给程序自身完成。
开发者只需要告诉Spring对象之间的依赖关系即可,实现细节由Spring通过反射的方式自动完成。
人为规定,我们把通过Spring IoC创建的组件叫做Bean。
下面有三种依赖注入的方式:
① set方法注入 例如StudentController中注入StudentService
// 第一步,在类中声明依赖关系 StudentService studentService; // 第二步,在类中声明一个set方法 public void setStudentService(StudentService studentService) { this.studentService= studentService; }// 第三步,在xml中”告诉“Spring如何依赖

但这种方式还是比较麻烦。
② 构造函数注入
// 第一步,声明这个类是Spring组件,例如@RestController或@Service等 @RestController @RequestMapping("student") public class StudentController { ... }// 第二步,声明依赖关系的变量,必须为private final private final StudentService studentService; // 第三步,在构造函数中声明想要注入的变量 public StudentController(StudentService studentService) { this.studentService = studentService; }

③ @Autowired注入
// 第一步,声明这个类是Spring组件,例如@RestController或@Service等 @RestController @RequestMapping("student") public class StudentController { ... }// 第二步,声明依赖关系的变量,必须为private final private final StudentService studentService; // 第三步,在依赖关系上加入@Autowired注解 @Autowired private final StudentService studentService;

简单来说,Spring为我们准备了一个容器,来放置这些依赖。
所谓容器,就是一个容纳东西的物品,现实中的容器包括水杯、水壶、冰箱等等。
Spring容器给这些对象提供了空间,在需要装配的对象的时候,Spring会按照依赖关系,按顺序实例化这些对象,并且放置到容器中。
这些容器中的对象,将会由Spring维护,并且遵循单例模式,也就是说,全局只有一个此类的实例化对象。
当其他对象也依赖容器里已有的对象时,会直接提供容器内的引用(指针)。
三、总结 总之,IoC使对象的调用与对象关系的维护分离开来,用户在使用对象时,不必在手动实例化、手动装配,也不再需要关注它的生命周期,只需要把精力集中在对象功能上即可。
此外,IoC通过单例模式,避免了冗余的对象,降低资源消耗,也让Beans可以共享,让软件执行的逻辑更加符合业务逻辑。
后记 这篇文章怎么来的 准确的说,是我先学习廖雪峰老师的教程,然后结合自己的理解重新默写了一遍,目的只是为了加深理解。
所以一定会有重复的内容,并非抄袭。
参考资料: 【初识Spring IoC】https://www.liaoxuefeng.com/w...

    推荐阅读