IOC 原理
SpringIOC实现原理
1. 依赖倒置
假设我们设计一辆汽车:先设计轮子,然后根据轮子大小设计底盘,接着根据底盘设计车身,最后根据车身设计好整个汽车。这里就出现了一个“依赖”关系:汽车依赖车身,车身依赖底盘,底盘依赖轮子。

这样的设计看起来没问题,但是可维护性却很低。假设设计完工之后,上司却突然说根据市场需求的变动,要我们把车子的轮子设计都改大一码。这下我们就蛋疼了:因为我们是根据轮子的尺寸设计的底盘,轮子的尺寸一改,底盘的设计就得修改。
同样因为我们是根据底盘设计的车身,那么车身也得改,同理汽车设计也得改——整个设计几乎都得改!我们现在换一种思路。我们先设计汽车的大概样子,然后根据汽车的样子来设计车身,根据车身来设计底盘,最后根据底盘来设计轮子。这时候,依赖关系就倒置过来了:轮子依赖底盘, 底盘依赖车身, 车身依赖汽车。

这时候,上司再说要改动轮子的设计,我们就只需要改动轮子的设计,而不需要动底盘,车身,汽车的设计了。这就是依赖倒置原则——把原本的高层建筑依赖底层建筑“倒置”过来,变成底层建筑依赖高层建筑。高层建筑决定需要什么,底层去实现这样的需求,但是高层并不用管底层是怎么实现的。这样就不会出现前面的“牵一发动全身”的情况。
2. 控制反转(Inversion of Control)
就是依赖倒置原则的一种代码设计的思路。具体采用的方法就是所谓的依赖注入(Dependency Injection)。其实这些概念初次接触都会感到云里雾里的。说穿了,这几种概念的关系大概如下:

为了理解这几个概念,我们还是用上面汽车的例子。只不过这次换成代码。我们先定义四个Class:车、车身,底盘,轮胎。然后初始化这辆车,最后跑这辆车。代码结构如下:

这样,就相当于上面第一个例子,上层建筑依赖下层建筑——每一个类的构造函数都直接调用了底层代码的构造函数。假设我们需要改动一下轮胎(Tire)类,把它的尺寸变成动态的,而不是一直都是30。我们需要这样改:

由于我们修改了轮胎的定义,为了让整个程序正常运行,我们需要做以下改动:

由此我们可以看到,仅仅是为了修改轮胎的构造函数,这种设计却需要修改整个上层所有类的构造函数!在软件工程中,这样的设计几乎是不可维护的——在实际工程项目中,有的类可能会是几千个类的底层,如果每次修改这个类,我们都要修改所有以它作为依赖的类,那软件的维护成本就太高了。所以我们需要进行控制反转(IOC),及上层控制下层,而不是下层控制着上层。
我们用依赖注入(Dependency Injection)这种方式来实现控制反转。所谓依赖注入,就是把底层类作为参数传入上层类,实现上层类对下层类的“控制”。这里我们用构造方法传递的依赖注入方式重新写车类的定义:

这里我们再把轮胎尺寸变成动态的,同样为了让整个系统顺利运行,我们需要做如下修改:

看到没?这里我只需要修改轮胎类就行了,不用修改其他任何上层类。这显然是更容易维护的代码。不仅如此,在实际的工程中,这种设计模式还有利于不同组的协同合作和单元测试:比如开发这四个类的分别是四个不同的组,那么只要定义好了接口,四个不同的组可以同时进行开发而不相互受限制。
对于单元测试,如果我们要写Car类的单元测试,就只需要Mock一下Framework类传入Car就行了,而不用把Framework、Bottom、Tire全部new一遍再来构造Car。这里我们是采用的构造函数传入的方式进行的依赖注入。其实还有另外两种方法:Setter传递和接口传递。这里就不多讲了,核心思路都是一样的,都是为了实现控制反转。

3. 控制反转容器(IOC Container)
其实上面的例子中,对车类进行初始化的那段代码发生的地方,就是控制反转容器。

显然你也应该观察到了,因为采用了依赖注入,在初始化的过程中就不可避免的会写大量的new。这里IOC容器就解决了这个问题。这个容器可以自动对你的代码进行初始化,你只需要维护一个Configuration(可以是xml可以是一段代码),而不用每次初始化一辆车都要亲手去写那一大段初始化的代码。这是引入IOC Container的第一个好处。IOC Container的第二个好处是:我们在创建实例的时候不需要了解其中的细节。在上面的例子中,我们自己手动创建一个车instance时候,是从底层往上层new的:

这个过程中,我们需要了解整个Car/Framework/Bottom/Tire类构造函数是怎么定义的,才能一步一步new注入。而IOC Container在进行这个工作的时候是反过来的,它先从最上层开始往下找依赖关系,到达最底层之后再往上一步一步new(有点像深度优先遍历):

作者:窜天猴Plus
链接:https://www.jianshu.com/p/ad05cfe7868e
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
IOC 原理的更多相关文章
- Java反射机制及IoC原理
一. 反射机制概念 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义.在java中,只要给定类的名字, 那么就可以通 ...
- 【Spring】Spring IOC原理及源码解析之scope=request、session
一.容器 1. 容器 抛出一个议点:BeanFactory是IOC容器,而ApplicationContex则是Spring容器. 什么是容器?Collection和Container这两个单词都有存 ...
- IOC原理分析
IOC(inversion of control)控制反转 在我们的程序中,要实现某个功能,我们都会用到两个或两个以上的类来协同完成,那么在一个类中,我们就会要有它的合作类的引用,也就是说这个类依赖于 ...
- Spring的IOC原理[通俗解释一下]
Spring的IOC原理[通俗解释一下] 1. IoC理论的背景我们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑. 图 ...
- spring原理案例-基本项目搭建 03 创建工程运行测试 spring ioc原理实例示例
下面开始项目的搭建 使用 Java EE - Eclipse 新建一 Dynamic Web Project Target Runtime 选 Apache Tomcat 7.0(不要选 Apache ...
- Spring之IOC原理及代码详解
一.什么是IOC 引用 Spring 官方原文:This chapter covers the Spring Framework implementation of the Inversion of ...
- 1.IOC原理模拟
Spring两大核心功能,IOC(Inverse of Control) 和 AOP(Aspect-Oriented-Programming) IOC原理模拟: 有这样一个beans.xml: ...
- 【SpringBoot】 理解Spirng中的IOC原理
前言 前文已经介绍了Spring Bean的生命周期,在这个周期内有一个重要的概念就是: IOC容器 大家也知道IOC是Sping 的重要核心之一,那么如何理解它呢,它又是产生什么作用呢?本文就IOC ...
- Spring IOC原理补充(循环依赖、Bean作用域等)
文章目录 前言 正文 循环依赖 什么是循环依赖? Spring是如何解决循环依赖的? 作用域实现原理以及如何自定义作用域 作用域实现原理 自定义Scope BeanPostProcessor的执行时机 ...
- Spring IOC 原理深层解析
1 Spring IOC概念认识 1.1 区别IOC与DI 首先我们要知道IOC(Inverse of Control:控制反转)是一种设计思想,就是 将原本在程序中手动创建对象的控制权,交由Spri ...
随机推荐
- js替换指定位置字符串
var str='QWER';//替换WE newstr=replacepos(str,1,2,'XX'); console.log(newstr);//QXXR; function replacep ...
- Cobalt Strike简单使用
---恢复内容开始--- 一.介绍: 后渗透测试工具,基于Java开发,适用于团队间协同作战,简称“CS”. CS分为客户端和服务端,一般情况下我们称服务端为团队服务器,该工具具有社工功能(社会工程学 ...
- C++ Templates (2.1 类模板Stack的实现 Implementation of Class Template Stack)
返回完整目录 目录 2.1 类模板Stack的实现 Implementation of Class Template Stack 2.1.1 声明类模板 Declaration of Class Te ...
- Magento add product attribute and assign to all group
$attributes = array( 'product_type' => array( 'type' => 'int', 'input' => 'select', 'source ...
- DVWA之文件包含(一)
文件包含又可以是本地文件包含或远程文件包含. 本地文件包含:文件存在本地目录 远程文件包含:文件共享或存在网络上,需要访问 <?php // The page we wish to displa ...
- go语言字符串的处理与json转换
1 字符串的处理 可以通过Go标准库中的strings和strconv两个包中的函数进行相应的操作 1 字符串的操作 func Contains(s, substr string) bool 字符串s ...
- PyTorch入门-CIFAR10图像分类
CIFAR10数据集下载 CIFAR10数据集包含10个类别,图像尺寸为 3×32×32 官方下载地址很慢,这里给一个百度云: https://pan.baidu.com/s/1oTvW8wNa-VO ...
- 记得设置docker日志文件大小!!!!!
# vim /etc/docker/daemon.json { "log-driver":"json-file", "log-opts": ...
- 2020重新出发,MySql基础,性能优化
@ 目录 MySQL性能优化 MySQL性能优化简述 使用 SHOW STATUS 命令 使用慢查询日志 MySQL 查询分析器 EXPLAIN DESCRIBE 索引对查询速度的影响 MySQL优化 ...
- composer版本号前面`^`和`~`的区别
~1.2.3表示: 1.2.3 <= 版本号 < 1.3.0 ^1.2.3表示: 1.2.3 <= 版本号 < 2.0.0 ~1.2 表示: 1.2.0 <= 版本号 & ...