IoC:Inversion of Control,控制反转
DI:Dependency Injection,依赖注入

要理解上面两个概念,就必须搞清楚如下的问题:

参与者都有谁?
依赖:谁依赖于谁?为什么需要依赖?
注入:谁注入于谁?到底注入什么?
控制反转:谁控制谁?控制什么?为什么叫反转(有反转就应该有正转了)?
依赖注入和控制反转是同一概念吗?

下面就来简要地回答一下上述问题,把这些问题搞明白了,也就明白IoC/DI了。
(1)参与者都有谁:一般有三方参与者,一个是某个对象;另一个是IoC/DI容器(譬如Spring);还有一个是某个对象的外部资源。
Tips:某个对象指的是任意的、普通的Java对象;IoC/DI的容器简单点说就是指用来实现IoC/DI功能的一个框架程序;
对象的外部资源指的就是对象需要的,但是是从对象外部获取的,都统称为资源,譬如,对象需要的其它对象,或者是对象需要的文件资源等。

(2)谁依赖于谁:当然是某个对象依赖于IoC/DI的容器
(3)为什么需要依赖:对象需要IoC/DI的容器来提供对象需要的外部资源
(4)谁注入谁:很明显是IoC/DI的容器把某个对象需要的资源注入此对象
(5)到底注入什么:就是注入某个对象所需要的外部资源(相关依赖)
(6)谁控制谁:当然是IoC/DI的容器来控制对象了。 谁来控制依赖的创建
(7)控制什么:主要是控制对象实例的创建
(8)为何叫反转:反转是相对于正向而言的,那么什么算是正向的呢? 正反是由写代码的历史顺序定的

考虑一下常规情况下的应用程序,如果要在A里面使用C,你会怎么做呢?
一般会使用组合,直接去创建C的对象,也就是说,在A类中主动去获取需要的外部资源C,这种情况被称为正向的。
那么什么是反向呢?就是A类不再主动去获取C,而是被动等待,等待IoC/DI的容器获取一个C的实例,然后反向地注入到A类中
主动去取是正向,被动接收就反向,从正向改为反向,就称为反转

(9)依赖注入和控制反转是同一概念吗?
依赖注入和控制反转是对同一事情的不同角度的描述。
依赖注入是强调某个对象获取需要的资源的方式;控制反转强调的是指某个对象在获取所需资源是主动还是被动
从某个方面讲,就是它们描述的角度不同。

依赖注入是从应用程序的角度去描述,可以把依赖注入描述得完整点:应用程序依赖容器创建并注入它所需要的外部资源(即相关依赖)
而控制反转是从容器的角度去描述,描述的完整点就是:容器控制应用程序,由容器反向地向应用程序注入其所需要的外部资源。

IoC/DI的进步是编程思想上“主从换位”的变化。
应用程序原来是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,
应用程序就变成被动的了,被动地等待IoC/DI容器来创建并注入它所需要的资源, 可以将关注点集中到核心业务上

IoC/DI的目标是代码复用、解耦。程序的体系结构也变得非常灵活。

《研磨设计模式》

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

IOC 理论

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

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

  1. 谁控制谁

  2. 控制什么

  3. 为何是反转

  4. 哪些方面反转了

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

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

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

已找女朋友为例(对于程序猿来说这个值得探究的问题)。一般情况下我们是如何来找女朋友的呢?首先我们需要根据自己的需求(漂亮、身材好、性格好)找一个妹子,然后到处打听她的兴趣爱好、微信、电话号码,然后各种投其所好送其所要,最后追到手。如下:

  1. /**

  2. * 年轻小伙子

  3. */

  4. public class YoungMan {

  5. private BeautifulGirl beautifulGirl;

  6. YoungMan(){

  7. // 可能你比较牛逼,指腹为婚

  8. // beautifulGirl = new BeautifulGirl();

  9. }

  10. public void setBeautifulGirl(BeautifulGirl beautifulGirl) {

  11. this.beautifulGirl = beautifulGirl;

  12. }

  13. public static void main(String[] args){

  14. YoungMan you = new YoungMan();

  15. BeautifulGirl beautifulGirl = new BeautifulGirl("你的各种条件");

  16. beautifulGirl.setxxx("各种投其所好");

  17. // 然后你有女票了

  18. you.setBeautifulGirl(beautifulGirl);

  19. }

  20. }

这就是我们通常做事的方式,如果我们需要某个对象,一般都是采用这种直接创建的方式( newBeautifulGirl()),这个过程复杂而又繁琐,而且我们必须要面对每个环节,同时使用完成之后我们还要负责销毁它,在这种情况下我们的对象与它所依赖的对象耦合在一起。

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

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

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

在没有引入 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方法注入、接口注入。

构造器注入

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

  1. YoungMan(BeautifulGirl beautifulGirl){

  2. this.beautifulGirl = beautifulGirl;

  3. }

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

setter 方法注入

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

  1. public class YoungMan {

  2. private BeautifulGirl beautifulGirl;

  3. public void setBeautifulGirl(BeautifulGirl beautifulGirl) {

  4. this.beautifulGirl = beautifulGirl;

  5. }

  6. }

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

接口方式注入

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

各个组件

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

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

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

Resource体系

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

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

BeanFactory 体系

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

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

Beandefinition 体系

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

BeandefinitionReader体系

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

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

https://mp.weixin.qq.com/s/7Ue7Kg4adTNW55q_9X4nxw

IOC DI 专题的更多相关文章

  1. 6. Laravel5学习笔记:IOC/DI的理解

    介绍 IOC 控制反转 Inversion of Control 依赖关系的转移 依赖抽象而非实践 DI 依赖注入 Dependency Injection 不必自己在代码中维护对象的依赖 容器自己主 ...

  2. 关于依赖注入IOC/DI的感想

    之前一直不明白依赖注入有什么好处,甚至觉得它是鸡肋,现在想想,当时真是可笑. 这个想法正如同说接口是没有用处一样. 当整个项目非常庞大,各个方法之间的调用非常复杂,那么,可以想象一下,假设说没有任何的 ...

  3. Spring IOC/DI和AOP原理

    一 IOC/DI 1. 概念机原理 IOC: Inversion of Control(控制反转)是一种设计思想,就是容器控制应用程序所需要外部资源的创建和管理,然后将其反转给应用程序.对象及其依赖对 ...

  4. 深入理解IoC/DI

    ------------------------------------------------------------------------ 理解IoC/DI 1.控制反转 --> 谁控制谁 ...

  5. IoC/DI基本思想的演变

    ---------------------------------------------------------------------------------- (1)IoC/DI的概念 IoC ...

  6. 话说IOC(DI)

    什么是IOC(DI) 书上的东东,因为说的太严谨,所以不太容易懂,其实也没那么复杂. 举几个例子: 1.文明点的:中午太热,不想出去吃饭,所以希望同事能帮忙带饭,现在有了点外卖平台,我们就可以直接在网 ...

  7. 工厂方法模式与IoC/DI

    IoC——Inversion of Control  控制反转 DI——Dependency Injection   依赖注入 1:如何理解IoC/DI        要想理解上面两个概念,就必须搞清 ...

  8. spring 依赖注入(IOC DI)

    依赖注入(IOC DI) 依赖注入的两种方式: 1. set注入 Spring要求使用set注入方式的时候,Bean需要提供一个无参数的构造方法.并提供一个属性的setter方法.例如: packag ...

  9. spring--学习之IOC DI

    2.1.1  IoC是什么 Ioc-Inversion of Control,即"控制反转",不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器 ...

随机推荐

  1. Rancher介绍安装以及对docker的管理

    原文:Rancher介绍安装以及对docker的管理 一.简介 Rancher是一个开源的企业级全栈化容器部署及管理平台.Rancher为容器提供一揽子基础架构服务:CNI兼容的网络服务.存储服务.主 ...

  2. C语言编译和链接

    编译链接是使用高级语言编程所必须的操作,一个源程序只有经过编译.链接操作以后才可以变成计算机可以理解并执行的二进制可执行文件. 编译是指根据用户写的源程序代码,经过词法和语法分析,将高级语言编写的代码 ...

  3. Qt资料大全

    简述 发福利了.发福利了.发福利了,重要的事情说三遍... 为了方便更多Qter了解.学习Qt,现将相关资源进行整理,主要内容包括:Qt官网.编码风格.GitHub & Third-Party ...

  4. linux系统调用表(system call table)

    系统调用号 函数名 入口点 源码 0 read sys_read fs/read_write.c 1 write sys_write fs/read_write.c 2 open sys_open f ...

  5. mfc 链接 access 2007 数据库

    神马也不说了,直接给出源代码和project 原理这个东西 Google  下.都出来了.自己就说下作为新手 , 1 应该打印出,链接错误原因 2 应该将数据库放到project以下,特别注意这点 给 ...

  6. Cube Simulation zoj3429 模拟

    Description Here's a cube whose size of its 3 dimensions are all infinite. Meanwhile, there're 6 pro ...

  7. 14.mocha+should.js

    转自http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html 众所周知对于任何一个项目来说,做好单元测试都是必不 ...

  8. react --- 路由传参的几种方式

    1.params 优势 : 刷新地址栏,参数依然存在缺点:只能传字符串,并且,如果传的值太多的话,url会变得长而丑陋. 2.query 优势:传参优雅,传递参数可传对象:缺点:刷新地址栏,参数丢失 ...

  9. HDU 4786Fibonacci Tree(最小生成树)

    Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission( ...

  10. Android Gallery和ImageSwitcher同步自动(滚动)播放图片库

    本文主要内容是如何让Gallery和ImageSwitcher控件能够同步自动播放图片集 ,看起来较难,然而,实现的方法非常简单, 请跟我慢慢来.总的来说,本文要实现的效果如下图:(截图效果不怎么好) ...