【死磕 Spring】----- IOC 之深刻理解 Spring IoC

在一开始学习 Spring 的时候,咱们就接触 IoC 了,做为 Spring 第一个最核心的概念,咱们在解读它源码以前必定须要对其有深刻的认识,本篇为【死磕 Spring】系列博客的第一篇博文,主要介绍 IoC 基本概念和各个组件。html

IOC 理论

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

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

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

在回答这四个问题以前,咱们先看 IOC 的定义:微信

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

上面这句话是整个 IoC 理论的核心。如何来理解这句话?咱们引用一个例子来走阐述(看完该例子上面四个问题也就不是问题了)。ide

已找女友为例(对于程序猿来讲这个值得探究的问题)。通常状况下咱们是如何来找女友的呢?首先咱们须要根据本身的需求(漂亮、身材好、性格好)找一个妹子,而后处处打听她的兴趣爱好、微信、电话号码,而后各类投其所好送其所要,最后追到手。以下:源码分析

/**
 * 年轻小伙子
 */
public class YoungMan {
    private BeautifulGirl beautifulGirl;

    YoungMan(){
        // 可能你比较牛逼,指腹为婚
        // beautifulGirl = new BeautifulGirl();
    }

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

    public static void main(String[] args){
        YoungMan you = new YoungMan();
        BeautifulGirl beautifulGirl = new BeautifulGirl("你的各类条件");
        beautifulGirl.setxxx("各类投其所好");

        // 而后你有女票了
        you.setBeautifulGirl(beautifulGirl);
    }
}

这就是咱们一般作事的方式,若是咱们须要某个对象,通常都是采用这种直接建立的方式(new BeautifulGirl()),这个过程复杂而又繁琐,并且咱们必需要面对每一个环节,同时使用完成以后咱们还要负责销毁它,在这种状况下咱们的对象与它所依赖的对象耦合在一块儿。学习

其实咱们须要思考一个问题?咱们每次用到本身依赖的对象真的须要本身去建立吗?咱们知道,咱们依赖对象其实并非依赖该对象自己,而是依赖它所提供的服务,只要在咱们须要它的时候,它可以及时提供服务便可,至于它是咱们主动去建立的仍是别人送给咱们的,其实并非那么重要。再说了,相比于本身千辛万苦去建立它还要管理、善后而言,直接有人送过来是否是显得更加好呢?this

这个给咱们送东西的“人” 就是 IoC,在上面的例子中,它就至关于一个婚介公司,做为一个婚介公司它管理着不少男男女女的资料,当咱们须要一个女友的时候,直接跟婚介公司提出咱们的需求,婚介公司则会根据咱们的需求提供一个妹子给咱们,咱们只须要负责谈恋爱,生猴子就好了。你看,这样是否是很简单明了。spa

诚然,做为婚介公司的 IoC 帮咱们省略了找女友的繁杂过程,将原来的主动寻找变成了如今的被动接受(符合咱们的要求),更加简洁轻便。你想啊,原来你还得鞍马先后,各类巴结,什么东西都须要本身去亲力亲为,如今好了,直接有人把现成的送过来,多么美妙的事情啊。因此,简单点说,IoC 的理念就是让别人为你服务,以下图(摘自Spring揭秘):

201805071001

在没有引入 IoC 的时候,被注入的对象直接依赖于被依赖的对象,有了 IoC 后,二者及其余们的关系都是经过 Ioc Service Provider 来统一管理维护的。被注入的对象须要什么,直接跟 IoC Service Provider 打声招呼,后者就会把相应的被依赖对象注入到被注入的对象中,从而达到 IOC Service Provider 为被注入对象服务的目的。因此 IoC 就是这么简单!原来是须要什么东西本身去拿,如今是须要什么东西让别人(IOC Service Provider)送过来

如今在看上面那四个问题,答案就显得很是明显了:

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

妹子有了,可是如何拥有妹子呢?这也是一门学问。

  1. 可能你比较牛逼,刚刚出生的时候就指腹为婚了。
  2. 大多数状况咱们仍是会考虑本身想要什么样的妹子,因此仍是须要向婚介公司打招呼的。
  3. 还有一种状况就是,你根本就不知道本身想要什么样的妹子,直接跟婚介公司说,我就要一个这样的妹子。

因此,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;
    }
}

相比于构造器注入,setter 方式注入会显得比较宽松灵活些,它能够在任什么时候候进行注入(固然是在使用依赖对象以前),这就比如你能够先把本身想要的妹子想好了,而后再跟婚介公司打招呼,你能够要林志玲款式的,赵丽颖款式的,甚至凤姐哪款的,随意性较强。

接口方式注入

接口方式注入显得比较霸道,由于它须要被依赖的对象实现没必要要的接口,带有侵入性。通常都不推荐这种方式。


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

各个组件

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

spring-201805091002

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

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

Resource体系

Resource,对资源的抽象,它的每个实现类都表明了一种资源的访问策略,如ClasspathResource 、 URLResource ,FileSystemResource 等。

spring-201805091003

有了资源,就应该有资源加载,Spring 利用 ResourceLoader 来进行统一资源加载,类图以下:

spring-201805091004

BeanFactory 体系

BeanFactory 是一个很是纯粹的 bean 容器,它是 IOC 必备的数据结构,其中 BeanDefinition 是她的基本结构,它内部维护着一个 BeanDefinition map ,并可根据 BeanDefinition 的描述进行 bean 的建立和管理。

spring-201805101001

BeanFacoty 有三个直接子类 ListableBeanFactoryHierarchicalBeanFactoryAutowireCapableBeanFactoryDefaultListableBeanFactory 为最终默认实现,它实现了全部接口。

Beandefinition 体系

BeanDefinition 用来描述 Spring 中的 Bean 对象。

spring-201805101002

BeandefinitionReader体系

BeanDefinitionReader 的做用是读取 Spring 的配置文件的内容,并将其转换成 Ioc 容器内部的数据结构:BeanDefinition。

spring-201805101003

ApplicationContext体系

这个就是大名鼎鼎的 Spring 容器,它叫作应用上下文,与咱们应用息息相关,她继承 BeanFactory,因此它是 BeanFactory 的扩展升级版,若是BeanFactory 是屌丝的话,那么 ApplicationContext 则是名副其实的高富帅。因为 ApplicationContext 的结构就决定了它与 BeanFactory 的不一样,其主要区别有:

  1. 继承 MessageSource,提供国际化的标准访问策略。
  2. 继承 ApplicationEventPublisher ,提供强大的事件机制。
  3. 扩展 ResourceLoader,能够用来加载多个 Resource,能够灵活访问不一样的资源。
  4. 对 Web 应用的支持。

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

spring-201805101004

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

此系列博文为 LZ 学习、研究 Spring 机制和源码的学习笔记,会涉及参考别人的博文和书籍内容,若有雷同,纯属借鉴,固然 LZ 会标明参考来源。同时因为知识面和能力的问题,文章中不免会出现错误之处,若有,望各位大佬指出,不胜感激
LZ 写此系列博客时,Spring 最新版本为 5.0.6.RELEASE ,因此此系列博客全部源码来源均为 5.0.6.RELEASE

相关文章
相关标签/搜索