Spring学习(一):理解IoC容器
序言
记得刚毕业那会儿,出来招工作被问到Spring的核心时,都觉得简单的一笔,直接说不就是IoC(控制反转)和DI(依赖注入)么,然后省略一万字对两个名词的解释。最近空来整理了一下Spring中IoC的相关概念,即是复习,也是希望分享出来能帮助到大家更快理解IoC。
其实IoC包括依赖查找(DL)和依赖注入(DI);只不过DL因为有侵入性 (它需要用户自己去是使用 API 进行查找资源和组装对象),已经被抛弃。所以现在提到IoC,更多的想到的就是依赖注入(DI)了。
依赖注入(DI)包括Set注入和构造器注入!其实还有一个通过实现接口的方式实现依赖注入,不过不常用,就不说了。
如图所示:

但其实 IOC 和DI 相当于一回事,只不过是看待问题的角度不同而已:
IOC: Spring 反向控制应用程序需要的资源。
DI: 应用程序依赖Spring为其提供资源。
IOC 是站在Spring 的角度,而DI 是站在应用程序的角度。
如下图所示:

接下来详细介绍一下IoC,从其初始化到实现过程,细细理解!
IoC粗理解
IoC亦称为“依赖倒置原理”(Dependency Inversion Principle),几乎所有框架都使用了倒置注入(Martin Fowler)技巧,是IoC原理的一项应用。SmaIITaIk、C++、Java和.NET面向对象语言的程序员已使用了这些原理。但是Spring是Java语言实现中最著名的一个。同时,控制反转即是Spring框架的核心,也是Spring框架要解决的核心问题。
IoC细理解
由于很多对象的依赖关系和维护并不需要和系统运行状态有很强的关联性,所以可以把在面向对象编程中需要执行的诸如新建对象、为对象引用赋值等操作交由容器统一完成;这样一来,这些散落在不同代码中的功能相同的部分就集中成为容器的一部分,也就是面向对象系统的基础设施的一部分。同时,这些对象之间的相互依赖关系也是比较稳定的,一般不会随着应用的运行状态的改变而改变。
此时,IoC 容器控制了对象,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象这是正转,因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;这就解释了控制反转。
基于以上特性,这些对象使用IoC容器来管理,简直就是天作之合。虽然这些特性存在于应用系统中,但是应用系统并不承担管理这些对象的责任,而是通过依赖反转把责任交给了容器(也可以说是平台)。
有了以上这些基础知识储备,Spring IoC容器的原理也就不难理解了。
Spring中IoC的应用
在Spring中,Spring IoC提供了一个基本的JavaBean容器,通过IoC模式管理依赖关系,并通过依赖注入和AOP切面增强了为JavaBea月这样的POJO对象赋予事务管理、生命周期管理等基本功能。
IoC容器
容器的两种表现形式
Spring 作者 Rod Johnson设计了两个接口用以表示容器:BeanFactory和ApplicationContext
BeanFactory 粗暴简单,可以理解为就是个 HashMap,Key 是 BeanName,Value 是 Bean 实例。通常只提供注册(put),获取(get)这两个功能。我们可以称之为 “低级容器”。
ApplicationContext 可以称之为 “高级容器”。因为他比 BeanFactory 多了更多的功能。他继承了多个接口。因此具备了更多的功能。例如资源的获取,支持多种消息(例如 JSP tag 的支持),对 BeanFactory 多了工具级别的支持等待。所以你看他的名字,已经不是 BeanFactory 之类的工厂了,而是 “应用上下文”, 代表着整个大容器的所有功能。该接口定义了一个
refresh方法,此方法是所有阅读 Spring 源码的人的最熟悉的方法,用于刷新整个容器,即重新加载/刷新所有的 bean。
故我们可以认为直接的BeanFactory实现是IoC容器的基本形式,而各种ApplicationContext的实现是IoC容器的高级表现形式。所以亦可简单的把Spring IoC通过BeanFactory的实现当做低级容器;把ApplicationContext的实现当做高级容器。
此文我们主要讲解Spring 低级容器(BeanFactory)的 IoC;因为高级容器 ApplicationContext,它包含了低级容器的功能,当它执行 refresh 模板方法的时候,将刷新整个容器的 Bean。同时其作为高级容器,它包含了太多的功能,不仅仅是 IoC。它支持不同信息源头,支持 BeanFactory 工具类、支持层级容器、支持访问文件资源、支持事件发布通知、支持接口回调等等。

图片来源于:《Spring技术内幕:深入解析Spring架构与设计原理(第2版)》
BeanFactory的IoC实现过程:
IoC 在 Spring 里,只需要低级容器(BeanFactory)就可以实现,两个步骤:
- 1、加载配置文件,解析成 BeanDefinition 放在 Map 里。
- 2、调用 getBean 的时候,从 BeanDefinition 所属的 Map 里,拿出 Class 对象进行实例化,同时,如果有依赖关系,将递归调用 getBean 方法 —— 完成依赖注入。getBean的流程如下所示:

IoC容器初始化过程
值得注意的是,在这个过程中,一般不包含Bean侬赖注入的实现。
在Spring IoC的设计中,Bean定义的载入和依赖注入是两个独立的过程。依赖注入一般发生在应用第一次通过getBean向容器索取Bean的时候。
但有一个例外值得注意,在使用loc容器时有一个预实例化的配置,通过这个预实例化的配置(具体来说,可以通过为Bean定义信息中的lazyinit属性),用户可以对容器初始化过程作一个微小的控制,从而改变这个被设置了]azyinit属性的Bean的依赖注入过程。
举例来说,如果我们对某个Bean设置了lazyinit属性,那么这个Bean的依赖注入在IoC容器初始化时就预先完成了,而不需要等到整个初始化完成以后,第一次使用getBean时才会触发。
BeanDefinition的定位
对loC容器来说,它为管理POJO之间的依赖关系提供了帮助,但也要依据Spring的定义规则提供Bean定义信息。我们可以使用各种形式的Bean定义信息,其中比较熟悉和常用的是使用XML的文件格式。
在Bean定义方面,Spring为用户提供了很大的灵活性。在初始化IoC容器的过程中,首先需要定位到这些有效的Bean定义信息,这里Spring使用Resource接口来统一这些Bean定义信息,而这个定位由ResourceLoader来完成。
- 如果使用上下文,ApplicationContext本身就为客户提供了定位的功能。因为上下文本身就是DefaultResourceLoader的子类。
- 如果使用基本的BeanFactory作为loC容器,客户需要做的额外工作就是为BeanFactory指定相应的Resource来完成Bean信息的定位。
BeanDefinition的载入
信息的载入过程。对IoC容器来说,这个载入过程,相当于把定义的BeanDefinition在IoC容器中转化成一个spring内部表示的数据结构的过程。IoC容器对Bean的管理和依赖注入功能的实现,都是通过对其持有的BeanDefinition进行各种相关操作来完成的。这些BeanDefinition数据在IoC容器中通过一个HashMap来保持和维护。当然这只是一种比较简单的维护方式,如果需要提高IoC容器的性能和容量,完全可以自己做一些扩展。
IoC容器的依赖注入
IoC容器的初始化过程完成的主要工作是在IoC容器中建立BeanDefinition数据映射。但在此过程中并没有IoC容器对Bean依赖关系进行注入,那么IoC容器是怎样对Bean的依赖关系进行注入的呢?
假设当前IoC容器已经载入了用户定义的Bean信息,开始分析依赖注入的原理:
首先,依赖注入的过程是用户第一次向容器索要Bean时触发的,当然也有例外,也就是我们可以在BeanDefinition信息中通过控制lazy-init属性来让容器完成对Bean的预实例化。这个预实例化实际上也是一个完成依赖注入的过程,但它是在初始化的过程中完成的。
所以,当用户向IoC容器索要Bean时,如果读者还有印象,那么一定还记得在基本的IoC容器接口BeanFactory中,有一个getBean的接口定义,这个接口的实现就是触发依赖注入发生的地方(也就是依赖注入的入口);而依赖注入的发生是在容器中的BeanDefinition数据已经建立好的前提下才能完成的。
IoC小结
尽管可以用最简单的方式来描述IoC容器,将它视为一个hashMap,但只能说这个hashMap是容器的最基本的数据结构,而不是IoC容器的全部。
打个比方来讲,使用IoC后相当于IoC就是一个饮品店;以前的我们需要自己new对象,也就是需要自己买橙子,买榨汁机来榨果汁喝;而是用IoC后,我们只需要把需求(想喝橙汁)告诉它,然后由它给我们提供橙汁就可以了。这样子想,是不是IoC就感觉简单多了呢?
Spring IoC容器作为一个产品,其价值体现在一系列相关的产品特性上,这些产品特性以依赖反转模式的实现为核心,为用户更好地使用依赖反转提供便利,从而实现了一个完整的IoC容器产品。
参考文章:
- 1、《Spring技术内幕:深入解析Spring架构与设计原理(第2版)》
- 2、https://www.cnblogs.com/stateis0/p/9779011.html
- 3、https://blog.csdn.net/ljk126wy/article/details/87519003
Spring学习(一):理解IoC容器的更多相关文章
- Spring学习-理解IOC和依赖注入
最近刚买了一本介绍ssm框架的书,里面主要对Mybatis.spring.springmvc和redis做了很多的讲解,个人觉得虽然有的内容我看不懂,但是整体上还是不错的.最近正在学习中,一边学习一边 ...
- Spring学习记录1——IoC容器
IoC容器 1.1 IoC概述 Ioc(Inverse of Control,控制反转)是Spring容器的内核.对于软件来说,即某一接口具体实现类的选择控制权从调用类中移除,转交给第三方决定,即由 ...
- Spring学习一: Ioc容器
Spring 容器: Spring 容器是Spring框架的核心.Spring容器将创建Bean对象实例,把它们联系在一起,配置它们,并管理它们整个生命周期从创建到销毁.Spring 容器通 ...
- Spring核心原理之IoC容器初体验(2)
本文节选自<Spring 5核心原理> 1 IoC与DI基本概念 IoC(Inversion of Control,控制反转)就是把原来代码里需要实现的对象创建.依赖,反转给容器来帮忙实现 ...
- Spring系列14:IoC容器的扩展点
Spring系列14:IoC容器的扩展点 回顾 知识需要成体系地学习,本系列文章前后有关联,建议按照顺序阅读.上一篇我们详细介绍了Spring Bean的生命周期和丰富的扩展点,没有阅读的强烈建议先阅 ...
- spring学习(01)之IOC
spring学习(01)之IOC IOC:控制反转——Spring通过一种称作控制反转(IOC)的技术促进了低耦合.当应用了IOC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创 ...
- 基于nutz框架理解Ioc容器
同样我们从问题入手去验证以及去理解Ioc容器都做了哪些事情: 1.nutz是有几种方式获取需要容器管理bean的信息? 第一种是使用json格式的文件进行配置,如: 第二种:使用注解@IocBean ...
- spring 学习 AOP和IOC
自11开始接触三大框架,至今已俞5载, 当时风光无限的ssh,现在还在被广泛使用,并有扩大之势的只有spring了 spring主要特性,是广为使用的AOP(面向切面)和IOC(控制反转) 1.其中, ...
- spring之:XmlWebApplicationContext作为Spring Web应用的IoC容器,实例化和加载Bean的过程
它既是 DispatcherServlet 的 (WebApplicationContext)默认策略,又是 ContextLoaderListener 创建 root WebApplicationC ...
- Spring源码解析-ioc容器的设计
Spring源码解析-ioc容器的设计 1 IoC容器系列的设计:BeanFactory和ApplicatioContext 在Spring容器中,主要分为两个主要的容器系列,一个是实现BeanFac ...
随机推荐
- 基于opencv下对视频的灰度变换,高斯滤波,canny边缘检测处理,同窗体显示并保存
如题:使用opencv打开摄像头或视频文件,实时显示原始视频,将视频每一帧依次做灰度转换.高斯滤波.canny边缘检测处理(原始视频和这3个中间步骤处理结果分别在一个窗口显示),最后将边缘检测结果保存 ...
- 利用webmagic获取天猫评论
引言 爬取商品信息 爬取商品评论 数据清洗 1. 引言 现代网页往往其HTML只有基本结构,而数据是通过AJAX或其他方法获取后填充,这样的模式对爬虫有一定阻碍,但是熟练以后获取并不困难,本文以爬取天 ...
- python库pandas简介
pandas是基于numpy的数据分析模块,提供了大量标准模型和高效操作大型数据集所需要的工具. pandas主要提供了3种数据结构:1.Series,带标签的一维数组:2.DataFrame,带标签 ...
- c语言中realloc()函数解析
一.基本特性 1. realloc()函数可以重用或扩展以前用malloc().calloc()及realloc()函数自身分配的内存. 2. realloc()函数需两个参数:一个是包含地址的指针( ...
- python装饰器小计
1.装饰器:本质是函数,是用来给其他函数添加附加扩展功能的函数,其返回值是一个函数(函数指针) 2.装饰器作用:不改变函数源代码和函数调用方式的前提下添加函数的附加功能. 3.装饰器储备知识点: A. ...
- VMware下对Ubuntu进行扩充磁盘大小
今天用虚拟机的时候,发现虚拟机快满了,提示磁盘空间小,不得不扩充虚拟机空间.经过百度搜索,终于搞定了,记录如下 平台:VMware(10.0.3)+Ubuntu 14.04(32bit) 1.选择VM ...
- [python3.5][PyUserInput]模拟鼠标和键盘模拟
一.PyUserInput安装 python3.5的PyMouse和PyKeyboard模块都集成到了PyUserInput模块中.在python3.5中,直接安装PyUserInput模块即可 Py ...
- BZOJ_2820_YY的GCD_莫比乌斯反演
BZOJ_2820_YY的GCD_莫比乌斯反演 题意&分析: 首先f[i]非积性,但可以通过μ处理,所以我们考虑线筛 f[i*p]=μ[i*p/p']; 1.当i为质数时f[i]=1; 2.当 ...
- BZOJ_1260_[CQOI2007]涂色paint _区间DP
BZOJ_1260_[CQOI2007]涂色paint _区间DP 题意: 假设你有一条长度为5的木版,初始时没有涂过任何颜色.你希望把它的5个单位长度分别涂上红.绿.蓝.绿.红色,用一个长度为5的字 ...
- Git详解及github与gitlab使用
第一章 关于版本控制 第二章 GIT简介 第三章 GIT安装 第四章 初次运行GIT前配置 第五章 初始化仓库 第六章 GIT命令操作 第七章 GIT分支结构