【Java Web】 -> Spring 5 -> IOC 底层原理

Ⅰ IOC是什么

我简单总结一下 IOC 是什么:

  1. 控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理;
  2. 使用 IOC 的目的:降低耦合度。

我第一篇文章写了一个 Spring 的第一个case,实现的就是 IOC 的功能。

【Java Web】-> Spring 5 -> Spring 的下载 & 第一个样例

其实 IOC 也好, 里氏替换也好,包括24种设计模式,主要的目的都是一件事:解耦

当我们在一个对象里生成另一个对象时,这个过程耦合度是很高的,所以我们把这个过程交给 Spring,它来负责创建对象,生成对象,我们只需要用就好了,IOC 大概就是这样。

Ⅱ IOC 底层原理

IOC 底层主要用到了三个技术: XML 文件解析, 工厂模式,反射。

我从一个case说起,简单介绍一下程序解耦的一个演化过程。

比如我现在有两个类。UserService和UserDao,它们分别有一个方法 execute() 和 add()

在这里插入图片描述
现在 UserSeivice 的 execute() 方法要调用 UserDao 中的 add() 方法,我们先来用传统的方法做一下。
在这里插入图片描述
这样需要在 execute() 方法中先创建 UserDao 的对象,再进行调用。这样耦合度就很高。

这时候有一个模式就出现了,它就是工厂模式

我们建立一个工厂,让它来生成 UserDao 的对象,然后 UserService 要使用的时候调用 UserFactory 就可以了,这样就使得 UserDao 和 UserService 解耦了。

在这里插入图片描述
这里有同学可能会疑惑,那工厂不是就和这两个类都耦合了吗,哪里降低耦合度了,本来只有两个类有耦合,现在搅进来个第三者,不就更麻烦了吗?

这位同学提了个好问题。

我们一般用工厂,也不会就生成一个对象,而且一个对象也不一定就是只会被一个类来调用,如果很多类都要调用 UserDao,那它们都要去和 UserDao 耦合,但是有了工程,所有使用 UserDao 的类都可以直接通过工厂这个中间人来取得,就不需要再去自己和 UserDao 耦合了。

就像金融领域里的银行一样,银行中间商是为了降低信息的不确定性的,有中间商总比没有中间商方便很多,不然你每次贷款都要去自己找愿意给你放贷的人,就很耦合很麻烦嘛。

要知道,对象和对象之间是不可能完全没有耦合度的,我们要做的是尽可能降低耦合度,但是这里降到最低了吗?显然也是没有的,我们再继续看。

再进一步,我们使用 xml 文件解析和反射机制。我描述一下 Spring IOC 的过程。

在这里插入图片描述
这样如果你的 UserDao 的地址改了,其他的地方都不需要动,什么包都不需要改,只改一个配置文件的 class 属性里的地址就好了,这样耦合性是不是就非常低了?

绿色的第二步 return 的对象去哪里了呢?当然就是放在工厂里的,所以说 Spring IOC 的本质就是一个容器。IOC 的底层容器就是一个对象工厂。

Ⅲ IOC 容器的实现方式

Spring 提供 IOC 容器实现的两种方式(两个接口):

  1. BeanFactory
  2. ApplicationContext

这两个接口其实是可以互相替换的。我用我第一个case来举例。

在这里插入图片描述
在这里插入图片描述
这里我将 ApplicationContext 更改成 BeanFactory,一样没有错误。那我简单介绍一下它们俩的区别是什么。

① BeanFactory

BeanFactory 是 IOC 容器的基本实现,是 Spring 内部使用的一个接口,不提供给开发人员(也就是我们)使用。

当然你要使用,就像我上面一样,也没有人拦你。

BeanFactory 使用的懒汉模式,也就是当你获取对应的对象的时候,对象并不存在,BeanFactory这时才进行创建,然后返回给你。
在这里插入图片描述

② ApplicationContext

ApplicationContext 是 BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人员使用。

和 BeanFactory 不同的是,ApplicationContext 实现的是饿汉模式,也就是在第一步就已经完成了对象的生成,当用户从工厂种取的时候,对象已经存在了。
在这里插入图片描述

那 BeanFactory 的懒汉模式和 ApplicationContext 的饿汉模式哪个更好一点呢?可能有人会想,那还是 BeanFactory 的懒汉模式 好一点,这样就可以节省很多资源,用的时候再生成就好了。但是要知道,Spring 是结合我们的 web 项目一起使用的,我们最好把耗时耗资源的准备工作留给自己,也就是在服务器启动的时候,就把一切资源都创建好,对象都生成好放在工厂中,这样在服务器启动之后,用户直接使用就可以了。

我们来看一下 ApplicationContext 的实现类。我圈起来的两个是 ApplicationContext 最主要的两个实现类。
在这里插入图片描述
我还是用我的case来说明这两个的区别。

ClassPathXmlApplicationContext() 实现的是类路径,比如我的配置文件 bean1.xml 是写在 src 目录下的,所以直接写名字就好了。
在这里插入图片描述
对比的,FileSystemXmlApplicationContext() 需要写的是配置文件在系统中的绝对路径。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_45627684/article/details/113694701
今日推荐