IoC容器趣谈
今天我们来谈谈Spring的内核之一——IoC容器
大家可能会有这样的疑问:
”这玩意为啥要叫容器呢?好奇怪“
”容器不是装东西的吗?难道IoC容器也是用来装什么东西的?“
有上述两个想法的小伙伴,我觉得你们是非常聪明的,并且平时有思考的习惯。别着急,让我们慢慢往下看
IoC容器的两大重要概念
IoC理解
IoC(Inverse of Control)控制反转,是应用本身不再进行对象的创建和维护工作,而是将这些工作交给外部容器去进行,这样控制权转移给外部容器,反转了。
举个例子:假设你和女朋友打算出去旅游,准备自驾去西藏玩。女朋友让你做旅游攻略,以及沿途行程安排。你本以为这是一件容易的事情,但实际操作后你抱怨道:“md,这比我该bug还麻烦”
刚好这时候,手机上推来一条“*西藏小团8人游,珠峰下的星空,只需要2XXX...*”的消息。这下爽了,研究一下直接报团,一下子省去了许多步骤,你开始幻想美丽的旅途...
思路回来一下,这个过程就很形象的描述了控制反转,你对旅游 (对象) 的控制权交给了旅行社 (容器) 。
DI理解
DI(Dependency Injection) 依赖注入指组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。 依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。
还拿上述例子举例,当你把你的旅游计划告诉给你好久不见,外地工作 的好朋友。你朋友听完之后也十分心动呀,说想带着他女朋友也一起去。
“那正好一起呀,人多大家玩的开心”。于是你把链接推给你的好朋友,让他也购买你这个旅行团,于是你们现在是一个旅行团,并且可以一起玩喽
你和你的朋友逻辑上是有关系的,可是不在一个地方,又想在一起玩。于是进入同一个旅行社(容器),当你们在西藏开始玩的时候(运行期),你们就可以见面了。
说白了,就是对象不用你创建了,他们之间的关系你也别管了。
所以:IoC容器 = IoC(控制反转)+DI(依赖注入)
这就是为什么spring框架在整个项目中有“大管家”的称号了
对于上面两个概念理解清楚了,其实就IoC容器你已经快“吃透”了。但是光有概念还不行,我们还得有细节和操作
创建IoC容器的方式
有以下两种常用的方式:
//创建IoC容器 利用ApplicationContext的子类ClassPathXmlApplicationContext(方式一)
ClassPathXmlApplicationContext ioc =
new ClassPathXmlApplicationContext("ioc.xml");
//方式二 利用ApplicationContext的子类FileSystemXmlApplicationContext
FileSystemXmlApplicationContext ioc2 =
new FileSystemXmlApplicationContext("D:\\code\\SpringDemo\\src\\main\\resources\\ioc.xml");
从代码中可以看出,主要区别在于配置文件.xml的路径上,绝对路径和项目路径
其实还有两种方式也可以用于IoC容器的创建:
AnnotationConfigApplicationContext
直接加载上下文定义(仅限基于Java配置类使用)不使用XML文件,使用注解
XmlWebApplicationContext
读取Web应用下的XML配置文件并加载上下文定义 用于web项目里
那么我们在深挖一下,上述两个子类中都有ApplicationContext的字样,那这个应该也是个类,是怎么来的呢?
下面代码模拟其中原理
//通过BeanFactory类创建ApplicationContext容器
// 加载配置文件
ClassPathResource resource = new ClassPathResource("applicationContext.xml");
// 创建BeanFactory容器
BeanFactory beanFactory = new XmlBeanFactory(resource);
// 从容器中获取对象实例
MyBean myBean = (MyBean) beanFactory.getBean("myBean");
// 使用对象实例
myBean.doSomething();
原来是利用了BeanFactory这个类。其实ApplicationContext,它是 BeanFactory 的子类,更好的补充并实现了 BeanFactory 的。
网上查了资料,BeanFactory类似于Hashmap,键值对中分别装了对象的名称 和 对象 (这里的对象被称为bean 马上讲到)但它一般只有 get, put 两个功能,所以称之为“低级容器”。
而 ApplicationContext 多了很多功能,因为它继承了多个接口,可称之为“高级容器”。
下面的图片可以很好的对他们的关系进行理解
装配bean
刚才提到了一个名称 bean ,我用“对象”一词对他进行转义。
其实bean就是包装好了的对象(Object),Java本身是面向对象编程语言,任何操作都是围绕作者对象进行,在这里,由spring对其进行封装。
那装配bean又是什么意思?有点像给枪上子弹的感觉
装配bean就是在IoC容器中创建bean 以及确定bean和bean之间的依赖关系
Spring支持三种装配bean的方式
- 基于XML配置
- 基于注解
- 基于Java类配置
首先来看第一种,建立一个ioc.xml配置文件:
<!--创建Boy bean 相当于(Boy boy = new Boy())-->
<bean id="boy" class="ioc.Boy" />
<!--又创建Girl bean 相当于(Girl girl = new Girl)-->
<bean id="Girl" class="ioc.Girl"/>
第二种,通过注解:
依赖注入的方法
- 方法注入(推荐)
- 构造器注入
- 接口注入
注意:spring只支持前两种方式
看看下面男孩和女孩配对的例子 :
package ioc;
public class Boy {
private String name;
private int age;
private Girl girl;
public Boy() {
System.out.println("实例化boy");
}
public Boy(String name, int age) {
this.name = name;
this.age = age;
}
public Boy(Girl girl) {//构造器注入(方式一)
this.girl = girl;
}
public Boy(String name, int age, Girl girl) {
this.name = name;
this.age = age;
this.girl = girl;
System.out.println("构造器注入");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Girl getGirl() {
return girl;
}
public void setGirl(Girl girl) {//方法注入(方式二)
this.girl = girl;
System.out.println("方法注入girl");
}
@Override
public String toString() {
return "Boy{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
上述例子中我们定义了一个男孩类,男孩的属性为name,age,Girl(配对的女孩) ,女孩类的定义如下:
package ioc;
public class Girl {
private String name;
private int age;
public Girl() {
System.out.println("实例化girl");
}
public Girl(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Girl{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
传统来说我们会通过这种方式来设置属性和构造依赖关系
Boy boy = new Boy("张三",25,new Girl("小美",22))
但现在,我们会在ioc.xml文件中写(方法注入):
<bean id="Girl" class="ioc.Girl">
<!--相当于调用 setName("小美")-->
<property name = "name" value = "小美"/>
<property name = "age" value = "22"/>
</bean>
<!--创建Boy bean 相当于(Boy boy = new Boy())-->
<!--init-method设置初始化值 destroy-method用于销毁ioc-->
<bean id="boy" class="ioc.Boy" >
<!--给类的属性设置初始值-->
<property name="name" value="张三"/>
<property name="age" value="25"/>
<!--依赖注入(方法注入) 相当于调用了setGirl(girl)-->
<property name="girl" ref="Girl" />
</bean>
上述的是方法注入,还有一种spring支持的 构造器注入 如下:
<bean id="Girl" class="ioc.Girl">
<!--相当于调用 setName("小美")-->
<property name = "name" value = "小美"/>
<property name = "age" value = "22"/>
</bean>
<bean id="boy2" class="ioc.Boy" scope="prototype">
<constructor-arg value="李四"/>
<constructor-arg value="24"/>
<!--依赖注入(构造器注入)-->
<constructor-arg ref="Girl"/>
</bean>
注:构造器注入需要相应的构造器来进行
后续结果
通过上述的控制翻转和依赖注入,我们相当于完成了对象的设置,现在需要通过将我们输入的东西展示出来,代码如下:
package ioc;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class TestIoC {
public static void main(String[] args) {
//创建IoC容器(方式一)
ClassPathXmlApplicationContext ioc =
new ClassPathXmlApplicationContext("ioc.xml");
//方式二
// FileSystemXmlApplicationContext ioc2 =
// new FileSystemXmlApplicationContext("D:\\code\\SpringDemo\\src\\main\\resources\\ioc.xml");
// System.out.println("ioc2"+ioc2);
//获取IoC容器 的 Bean实例 (Boy对象实例)
/ Boy boy = (Boy) ioc.getBean("boy");
System.out.println("boy:"+boy);
Boy boy2 = (Boy) ioc.getBean("boy2");
System.out.println("boy2:"+boy2);
System.out.println(boy2.getGirl());
}
}
打印结果:
boy:Boy{name='张三', age=25}
boy2:Boy{name='李四', age=24}
Girl{name='小美', age=22}
额外提一嘴,getBean()有两种用法:name: bean的id ;class:bean的类型(容器内唯一)
具体怎么玩呢?请听下回分解
IoC容器趣谈的更多相关文章
- 1.3浅谈Spring(IOC容器的实现)
这一节我们来讨论IOC容器到底做了什么. 还是借用之前的那段代码 ClassPathXmlApplicationContext app = new ClassPathXmlApplicationCon ...
- 深入理解DIP、IoC、DI以及IoC容器
摘要 面向对象设计(OOD)有助于我们开发出高性能.易扩展以及易复用的程序.其中,OOD有一个重要的思想那就是依赖倒置原则(DIP),并由此引申出IoC.DI以及Ioc容器等概念.通过本文我们将一起学 ...
- 【最简单IOC容器实现】实现一个最简单的IOC容器
前面DebugLZQ的两篇博文: 浅谈IOC--说清楚IOC是什么 IoC Container Benchmark - Performance comparison 在浅谈IOC--说清楚IOC是什么 ...
- 深入理解DIP、IoC、DI以及IoC容器(转)
深入理解DIP.IoC.DI以及IoC容器 摘要 面向对象设计(OOD)有助于我们开发出高性能.易扩展以及易复用的程序.其中,OOD有一个重要的思想那就是依赖倒置原则(DIP),并由此引申出IoC.D ...
- 【转】深入理解DIP、IoC、DI以及IoC容器
原文链接:http://www.cnblogs.com/liuhaorain/p/3747470.html 前言 对于大部分小菜来说,当听到大牛们高谈DIP.IoC.DI以及IoC容器等名词时,有没有 ...
- IoC容器的初始化过程
1.简单来说,IoC容器的初始化是由前面介绍的refresh()方法来启动的,这个方法标志着IoC容器的正式启动. 2.具体来说,这个启动包括BeanDefinition的Resource定位.载入和 ...
- DIP、IoC、DI以及IoC容器
深入理解DIP.IoC.DI以及IoC容器 摘要 面向对象设计(OOD)有助于我们开发出高性能.易扩展以及易复用的程序.其中,OOD有一个重要的思想那就是依赖倒置原则(DIP),并由此引申出IoC.D ...
- Spring技术内幕总结 - IoC容器的实现
IoC:Inversion of Control,控制反转,即依赖对象的获得被反转了(DI:dependency inversion,依赖注入)在Spring中,IoC容器是实现这个模式的载体.它可以 ...
- 【来龙去脉系列】深入理解DIP、IoC、DI以及IoC容器
摘要 面向对象设计(OOD)有助于我们开发出高性能.易扩展以及易复用的程序.其中,OOD有一个重要的思想那就是依赖倒置原则(DIP),并由此引申出IoC.DI以及Ioc容器等概念.通过本文我们将一起学 ...
- 一个由正则表达式引发的血案 vs2017使用rdlc实现批量打印 vs2017使用rdlc [asp.net core 源码分析] 01 - Session SignalR sql for xml path用法 MemCahe C# 操作Excel图形——绘制、读取、隐藏、删除图形 IOC,DIP,DI,IoC容器
1. 血案由来 近期我在为Lazada卖家中心做一个自助注册的项目,其中的shop name校验规则较为复杂,要求:1. 英文字母大小写2. 数字3. 越南文4. 一些特殊字符,如“&”,“- ...
随机推荐
- vue+element 判断table表格输入不能为空
点击确定的时候,判断表格其中某行某值不能为空 1.HTML <div class="app-container"> <el-form ref="form ...
- AWVS14破解docker一键安装
先上个图 2021最新版 1.使用docker查看是否有awvs: [root@hadoop-01 awvs13-linux]# docker search awvs NAME ...
- 来会会babel这个重要且神奇的工具
babel 在前端工程化开发中发挥着至关重要的作用,它能将较高级的语法转成浏览器可识别的代码,无论中 es6 中 const .promise 还是 React.TypeScript. 以下babel ...
- C++函数参数匹配规则
C++ 函数参数匹配 1 单个参数匹配 void f(); //f1 void f(int); //f2 void f(int, int); //f3 void f(double, double=3. ...
- AI绘画创意文字全流程揭秘,你的终极文字艺术实操宝典
本教程收集于:AIGC从入门到精通教程汇总 AIGC技术不断更新迭代,国内出现了越来越多的新玩法,比如最近大家都在热议的AI绘画创意文字. 过去的一周,我把这些新玩法都研究了一遍,并总结了一套完整的制 ...
- 【译】通过 GitHub Copilot Chat 简化代码优化和调试(AI 辅助编程)
今年3月,我们宣布了 Visual Studio 2022 的 GitHub Copilot Chat.通过 Chat, Copilot 已经超越了代码补全,提供了对代码工作原理的深入分析和解释.它支 ...
- Flutter系列文章-Flutter在实际业务中的应用
不同场景下的解决方案 1. 跨平台开发: 在移动应用开发中,面对不同的平台(iOS和Android),我们通常需要编写两套不同的代码.而Flutter通过一套代码可以构建适用于多个平台的应用,大大提高 ...
- Jmeter关联之正则表达式提取器
正则表达式简介 摘自网上的说法,正则表达式是对字符串(包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符"))操作的一种 逻辑公式,就是用事先定义好的一些特定字符 ...
- 按关键字API接口搜索天眼查企业数据
一.如果你想要查找某一个企业的基本信息或是对行业中的企业进行筛选,那么使用API接口搜索天眼查企业数据会非常方便. 首先,你需要获取天眼查API的access_token,这可以通过注册账号获取.一旦 ...
- Java程序员学vue3最好的方式就是搭建后台管理模板
前言 作为Java程序员,vue3还是有必要学的,毕竟是国内最受欢迎的前端JS框架,你现在接手的项目,前端部分几乎都会和vue沾边,尤其是中小企业. vue3作为新的大版本,相较于vue2改动还是很多 ...