SpringIOC

1 IOC

1.1 IOC 概念

IOC,即控制反转(Iversion of Control),是一种设计思想;

  • 控制:控制对象的创建及销毁(生命周期)。
  • 反转:将对象的控制权交给IOC容器。

所有的类都会在Spring容器中注册,告诉Spring你是什么,你需要什么东西,然后Spring会在系统运行到适当的时候,把你需要的东西主动给你;

所有类的创建、销毁都由Spring来控制,即控制对象生命周期的不是引用它的对象,而是Spring;对于某个具体对象而言,以前是它控制其他对象,现在所有对象都被Spring控制;

1.2 依赖注入(DI)

依赖注入(Dependency Injection,DI)就是将底层类作为参数传递给上层类,实现上层对下层的控制,依赖注入实现控制反转。

举例说明依赖注入:以生产行李箱为例。

传统设计思路

先设计轮子,然后根据轮子 size 来设计底盘,再根据底盘来设计箱体,最后设计好行李箱。

可这样表示:
在这里插入图片描述
相应的代码如下:

在这里插入图片描述
size 是固定值,可以进行相应的改进:

在这里插入图片描述
使用依赖注入方式进行改进

先设计行李箱的大概样子,再根据行李箱的样子设计箱体,根据箱体去设计底盘,然后去设计轮子。

在这里插入图片描述
改进后相应的代码如下:

在这里插入图片描述
不难理解,依赖注入就是将底层类作为参数传递给上层类,实现上层对下层的控制。

1.3 IOC 和 DI 的关系

使用 DI 去实现 IOC。

DI 的 4 种方式:

  1. setter 注入
  2. 构造器注入
  3. 注解注入
  4. 接口注入

依赖倒置原则、IOC、DI 和 IOC 容器的关系:

在这里插入图片描述
使用 IOC 容器的好处

  1. 避免在各处使用 new 来创建类,并且可统一维护;
  2. 创建实例时,不需要了解其中的细节;

2 SpringIOC

2.1 IOC 容器的初始化过程

在这里插入图片描述

  • Resource 定位(即 BeanDefinition 的资源定位,Resource 为各种形式的 BeanDefinition 的使用都提供了统一的接口);
  • BeanDefinition 的载入;
  • 向 IoC 容器中注册 BeanDefinition (实际上 IOC 容器内部维护一个 HashMap,注册过程就是将 BeanDefinition 添加至 HashMap 中);

2.2 IOC 加载过程

在这里插入图片描述
IOC 容器其实就是一个大工厂,它用来管理我们所有的对象以及依赖关系:

  1. 根据 Bean 配置信息在容器内部创建 Bean 定义注册表;
  2. 根据注册表加载,实例化 Bean,建立 Bean 与 Bean 之间的依赖关系;
  3. 将 Bean 实例放入 Spring IOC 容器中,等待应用程序调用;

3 BeanFactory 和 ApplicationContext

3.1 BeanFactory

  1. IOC 容器要实现的最基础的接口;
  2. 采用延迟初始化策略(容器初始化完成后并不会创建 Bean 对象,只有当收到初始化请求时才进行初始化);
  3. 由于是延迟初始化策略,因此启动速度较快,占用资源较少;

3.2 ApplicationConext

  1. 在 BeanFactory 基础上,增加了更为高级的特性:事件发布、国际化等;
  2. 在容器启动时,完成所有 Bean 的创建;
  3. 启动时间较长,占用资源较多;

3.3 BeanFactory 和 FactoryBean 的区别

  • BeanFactory 是 IOC 最基本的容器,负责生产和管理 Bean,为其他具体的 IoC 容器提供了最基本的规范;
  • FactoryBean 是一个 Bean,是一个接口,当 IoC 容器中的 Bean 实现了 FactoryBean 后,通过 getBean(String beanName) 获取到的 Bean 对象并不是 FactoryBean 的实现类对象,而是这个实现类中的 getObject() 方法返回的对象。要想获取 FactoryBean 的实现类对象,就是在 beanName 前面加上 “&”;

4 getBean 代码逻辑

  • 获取参数 name 转化为 beanName
  • 从缓存中加载实例
  • 实例化 Bean
  • 检测 parentBeanFactory(若无缓存数据,直接到 parentBeanFactory 中去加载)
  • 初始化依赖的 Bean
  • 返回 Bean

5 Spring 中循环依赖

5.1 类的实例化和类的初始化

  • 类的实例化是指创建一个类的实例(对象)的过程;
  • 类的初始化是指为类中各个类成员(被static修饰的成员变量)赋初始值的过程,是类生命周期中的一个阶段;

在 Spring 容器中我们的类又是什么时候进行初始化和实例化的呢?

  • Spring 中所有 Bean 默认都是单例模式,所以 Bean 的初始化和实例化都是在加载进入 Bean 容器时做的;
  • 如果想使用时再初始化,那么可以把类定义为原型模式;

5.2 循环依赖

若 A 中有 B 的属性,B 中有 A 的属性,则当进行依赖注入时,就会产生 A 还未创建完,因为对 B 的创建再次返回创建 A。

5.3 解决循环依赖

单例对象,在 Spring IoC 容器中,有且仅有一个对象,将对象放入缓存中。Spring 中使用“三级缓存”:

  1. SingletonObjects:单例对象的缓存(存储实例化完成的 Bean);
  2. earlySingletonObjects:提前曝光的单例对象的缓存(存储正在实例化的 Bean);
  3. SingletonFactories:单例 ObjectFactory 的缓存;

举例说明解决循环依赖(A 中有B,B 中有 A)的具体过程:

Spring 中单例对象的初始化主要分为 3 步:

  • 第一步:createBeanInstance
  • 第二步:populateBean 填充属性
  • 第三步:intializeBean 初始化

在进行 createBeanInstance 后,该单例对象此时已被创建,Spring 将该对象提前曝光到 SingletonFacotries 中。

  1. A 完成 createBeanInstance ,并且提前曝光到 SingletonFacotries 中;
  2. A 进行第二步,发现需要依赖 B,尝试获取 B;
  3. B 开始创建,B 完成 createBeanInstance,发现需要依赖 A,尝试获取A:先尝试从 SingletonObjects 中获取,发现不存在,因为 A 未初始化完全;再尝试从 earlySingletonObjects 中获取;再去 SingletonFactories 中获取,此时 B 获取 A,并将 A 放入 earlySingletonObjects 中,再删除 A 在 SingletonFacotries 中对应的 ObjectFactory;
  4. B 获取 A,顺利完成第二、三步,并将初始化完成的 B 放入 SingletonObjects 中;
  5. 此时返回创建 A,A 可获取 B,顺利完成第二、三步,A 初始化完成, 将 A 放入 SingletonObjects 中;

注意:Spring 中循环依赖有 2 种:

  1. 构造器循环依赖:因为提前曝光到 SingletonFactories 中的前提是需要执行构造方法,所以使用 “三级缓存” 无法解决;
  2. setter 循环依赖;

5.4 总结

  1. 尽量不要使用基于构造器的 DI,使用基于 setter 的 DI;
  2. 使用 @Autowired 注解,让 Spring 决定合适的时机;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hellosc01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值