xinrong2019 / xinrong2019.github.io

My Blog
https://xinrong2019.github.io
1 stars 1 forks source link

[死磕Spring]--IoC之深入理解Spring IoC #120

Open xinrong2019 opened 4 years ago

xinrong2019 commented 4 years ago

【死磕 Spring】—— IoC 之深入理解 Spring IoC

1 IoC理论

IoC 全称为 Inversion of Control,翻译为 “控制反转”,它还有一个别名为 DI(Dependency Injection),即依赖注入。

如何理解“控制反转”好呢?理解好它的关键在于我们需要回答如下四个问题:

  1. 谁控制谁
  2. 控制什么
  3. 为何是反转
  4. 哪些方面反转了

在回答这四个问题之前,我们先看 IoC 的定义:

所谓 IoC ,就是由 Spring IoC 容器来负责对象的生命周期和对象之间的关系

  1. 谁控制谁:在传统的开发模式下,我们都是采用直接 new 一个对象的方式来创建对象,也就是说你依赖的对象直接由你自己控制,但是有了 IoC 容器后,则直接由 IoC 容器来控制。所以“谁控制谁”,当然是 IoC 容器控制对象
  2. 控制什么:控制对象。
  3. 为何是反转:没有 IoC 的时候我们都是在自己对象中主动去创建被依赖的对象,这是正转。但是有了 IoC 后,所依赖的对象直接由 IoC 容器创建后注入到被注入的对象中,依赖的对象由原来的主动获取变成被动接受,所以是反转。
  4. 哪些方面反转了:所依赖对象的获取被反转了。

1.1 注入形式

IoC Service Provider 为被注入对象提供被依赖对象有如下几种方式:构造方法注入、stter方法注入、接口注入。

① 构造器注入

构造器注入,顾名思义就是被注入的对象通过在其构造方法中声明依赖对象的参数列表,让外部知道它需要哪些依赖对象。

YoungMan(BeautifulGirl beautifulGirl) {
    this.beautifulGirl = beautifulGirl;
}

构造器注入方式比较直观,对象构造完毕后就可以直接使用,这就好比你出生你家里就给你指定了你媳妇。

② setter 方法注入

对于 JavaBean 对象而言,我们一般都是通过 getter 和 setter 方法来访问和设置对象的属性。所以,当前对象只需要为其所依赖的对象提供相对应的 setter 方法,就可以通过该方法将相应的依赖对象设置到被注入对象中。如下:

public class YoungMan {

    private BeautifulGirl beautifulGirl;

    public void setBeautifulGirl(BeautifulGirl beautifulGirl) {
        this.beautifulGirl = beautifulGirl;
    }

}

③ 接口方式注入

接口方式注入显得比较霸道,因为它需要被依赖的对象实现不必要的接口,带有侵入性。一般都不推荐这种方式。

《依赖注入的三种实现形式 —— 接口注入(Interface Injection)》

1.2 推荐文章

关于 IoC 理论部分,笔者不在阐述,这里推荐几篇博客阅读:

xinrong2019 commented 4 years ago

2. 各个组件

先看下图(摘自:http://singleant.iteye.com/blog/1177358

组件类图

该图为 ClassPathXmlApplicationContext 的类继承体系结构,虽然只有一部分,但是它基本上包含了 IoC 体系中大部分的核心类和接口。

下面我们就针对这个图进行简单的拆分和补充说明。

2.1 Resource 体系

org.springframework.core.io.Resource,对资源的抽象。它的每一个实现类都代表了一种资源的访问策略,如 ClassPathResource、RLResource、FileSystemResource 等。

Resource 类图

2.1.2 ResourceLoader 体系

有了资源,就应该有资源加载,Spring 利用 org.springframework.core.io.ResourceLoader来进行统一资源加载,类图如下:

ResourceLoader 类图

关于 Resource 和 ResourceLoader 的源码解析,见 《【死磕 Spring】—— IoC 之 Spring 统一资源加载策略》

2.2 BeanFactory 体系

org.springframework.beans.factory.BeanFactory,是一个非常纯粹的 bean 容器,它是 IoC 必备的数据结构,其中 BeanDefinition 是它的基本结构。BeanFactory 内部维护着一个BeanDefinition map ,并可根据 BeanDefinition 的描述进行 bean 的创建和管理。

BeanFactory 类图

2.3 BeanDefinition 体系

org.springframework.beans.factory.config.BeanDefinition ,用来描述 Spring 中的 Bean 对象。

BeanDefinition 类图

2.4 BeanDefinitionReader 体系

org.springframework.beans.factory.support.BeanDefinitionReader的作用是读取 Spring 的配置文件的内容,并将其转换成 Ioc 容器内部的数据结构 :BeanDefinition 。

关于 BeanDefinitionReader 的源码解析,见如下文章:

2.5 ApplicationContext 体系

org.springframework.context.ApplicationContext,这个就是大名鼎鼎的 Spring 容器,它叫做应用上下文,与我们应用息息相关。它继承 BeanFactory ,所以它是 BeanFactory 的扩展升级版,如果BeanFactory 是屌丝的话,那么 ApplicationContext 则是名副其实的高富帅。由于 ApplicationContext 的结构就决定了它与 BeanFactory 的不同,其主要区别有:

  1. 继承 org.springframework.context.MessageSource 接口,提供国际化的标准访问策略。
  2. 继承 org.springframework.context.ApplicationEventPublisher 接口,提供强大的事件机制。
  3. 扩展 ResourceLoader ,可以用来加载多种 Resource ,可以灵活访问不同的资源。
  4. 对 Web 应用的支持。

下图来源:https://blog.csdn.net/yujin753/article/details/47043143

ApplicationContext 类图

2.6 小结

上面五个体系可以说是 Spring IoC 中最核心的部分,后面博文也是针对这五个部分进行源码分析。其实 IoC 咋一看还是挺简单的,无非就是将配置文件(暂且认为是 xml 文件)进行解析(分析 xml 谁不会啊),然后放到一个 Map 里面就差不多了,初看有道理,其实要面临的问题还是有很多的,下面就劳烦各位看客跟着 LZ 博客来一步一步揭开 Spring IoC 的神秘面纱。

此系列博文为 LZ 学习、研究 Spring 机制和源码的学习笔记,会涉及参考别人的博文和书籍内容,如有雷同,纯属借鉴,当然 LZ 会标明参考来源。同时由于知识面和能力的问题,文章中难免会出现错误之处,如有,望各位大佬指出,不胜感激。

另外,通过上面五个体系,我们可以看出,IoC 主要由 spring-beansspring-context 项目,进行实现。