IOC是“Inversion of Control”的缩写,翻译过来就是“控制反转”。javascript
咱们先不深究其在Spring中的含义,先从字面上进行分析。打个比方来讲:结婚前你的工资彻底由你来支配,想怎么花就怎么花。结婚后变了,你的钱要上交给你媳妇了,你想花的时候得申请。此时你对工资的控制转变了,由原来的你控制,变成了你媳妇控制。这就是“控制反转”,原本属于你控制的事情,交由别人来控制,而你只在须要的时候进行获取就能够了。java
Spring全家桶地址框架
相信经过这个比喻你们对“控制反转”的含义都已经理解了,那么它在Spring中的体现就是:把建立对象的过程交给Spring来进行管理,从而作到将原来须要本身手动new对象,变成直接从Spring中获取。ide
这就就比如Spring中有一个容器,咱们将Bean放到这个容器中,让这个容器为咱们建立实例,当须要时咱们直接从这个容器中进行获取便可。这个容器的实现理念就是IOC。spa
使用IOC最大的好处就是减小了代码的耦合度,下降了程序的维护成本。可能不少人都知道这个道理,就是不太明白它究竟是怎么下降的,别慌下面让我来给你们讲解一下。翻译
假设如今有一道菜:宫保鸡丁。code
// 伪代码 public class KungPaoChicken { public static KungPaoChicken getKungPaoChicken(各类食材) { // 加工各类食材最终获得一份美味的宫爆鸡丁。 return KungPaoChicken; } }
若是如今不使用IOC,咱们想要吃到宫保鸡丁,那么就须要以下操做。xml
// 伪代码 public class Person() { // 采购各类食材 // 准备好各类食材经过KungPaoChicken获取到一份宫保鸡丁。 KungPaoChicken kungPaoChicken = KungPaoChicken.getKungPaoChicken(各类食材); }
代码之间的耦合关系图:对象
看起来也不难,也不麻烦对吧?blog
别着急下定论,如今只是一我的想要宫保鸡丁,假如如今有10我的都想要那?是否是有十份相同的代码?这10我的都和KungPaoChicken有耦合。又好比如今须要的食材有所改变,那这样的话是否是这10我的都须要调整代码?这么一来是否是发现这种实现方式一点也不友好。
使用IOC的作法如今咱们转变一下思路,再也不本身动手作了,咱们把这道菜的作法告诉饭店,让饭店来作。
// 伪代码 public class Restaurant { public static KungPaoChicken getKungPaoChicken() { // 处理食材,返回宫保鸡丁 retur KungPaoChicken; } }
转变以后的耦合关系图:
通过这样处理,就能够很大程度上解决上面的这些问题。
一、咱们将KungPaoChicken交给Restaurant(饭店)来进行管理,它的建立由Restaurant进行。
二、如今不管是1我的仍是10我的咱们只须要从Restaurant中进行获取就能够了。这样耦合就改变了,Person只须要和Restaurant发生耦合就能够了。
三、当KungPaoChicken有变更时,也不须要每一个人都变更,只须要Restaurant随之改变就能够了。
Spring的IOC容器就充当了上面案例中的Restaurant角色,咱们只须要告诉Spring哪些Bean须要Spring进行管理,而后经过指定的方式从IOC容器中获取便可。
Spring提供的IOC容器Spring提供了一个接口BeanFactory。这个接口是Spring实现IOC容器的顶级接口,这个接口是Spring内部使用的,并非专门为框架的使用者提供的。
咱们通常使用的是BeanFactory的子接口ApplicationContext接口,这个接口提供了更多而且更增强大的功能。
在ApplicationContext接口中有三个经常使用的实现类分别是:AnnotationConfigApplicationContext、FileSystemXmlApplicationContext、ClassPathXmlApplicationContext。
容器的建立须要读取配置文件或配置类,经过这些配置告诉Spring哪些bean是须要Spring来进行管理的。
注意:读取配置文件时,若是读取绝对路径时入参须要添加前缀“file:”,读取相对路径时入参须要添加“classpath:”。
做用:用于在全注解开发时,读取配置类的相关配置信息。
注意:经过@Configuration注解标注当前类为Spring的配置类
ApplicationContext context = new AnnotationConfigApplicationContext(自定义的配置类.class);
做用:默认加载classPath下的配置文件,也就是代码编译以后的classes文件夹下。
注意:使用ClassPathXmlApplicationContext读取相对路径时入参的“classpath:”是能够省略的。读取绝对路径时,须要在入参添加前缀“file:”。
示例代码
// 相对路径 ApplicationContext context = new ClassPathXmlApplicationContext("classpath:配置文件名称.xml"); ApplicationContext context = new ClassPathXmlApplicationContext("配置文件名称.xml"); // 绝对路径 ApplicationContext context = new ClassPathXmlApplicationContext("file:绝对路径下的配置文件路径");
做用:默认加载的是项目的所在路径下的配置文件。注意:对FileSystemXmlApplicationContext来讲读取绝对路径时的入参前缀“file:”是能够省略的,可是读取相对路径的入参“classpath:”是必须的。
示例代码
// 相对路径 ApplicationContext context = new FileSystemXmlApplicationContext("classpath:beans.xml"); // 绝对路径 ApplicationContext context = new FileSystemXmlApplicationContext("file:绝对路径下的配置文件路径"); ApplicationContext context = new FileSystemXmlApplicationContext("绝对路径下的配置文件路径"); // 直接从项目的路径下 ApplicationContext context = new FileSystemXmlApplicationContext("src\main\resources\配置文件名");Spring的IOC实现原理
Spring实现IOC容器的是经过:工厂 + 反射,实现的。
经过一张图来给你们讲解SpirngIOC的实现原理(基于XML配置文件)
若是是基于全注解形式的话,只是将读取配置文件的步骤改为了读取配置类,而后经过配置类获取须要建立实现的Bean,并经过反射将其建立。其总体实现思路和使用XML配置文件是同样的。