如何理解Spring中的控制反转(IoC)

作者: imule 分类: Java备忘 发布时间: 2023-02-02 14:40

一位身着赤褐色高领毛衣和白色手袋的女性侧面轮廓。她闭着眼睛抬头看。

"Contributing makes me feel like I'm being useful to the planet."

— Anna Wong, Volunteer

1.依赖倒置(DIP)和依赖注入(DI)是一样的吗?

依赖倒置原则

a.高层模块不应该依赖于底层模块,二者都应该依赖于抽象。

b.抽象不应该依赖于细节,细节应该依赖于抽象。

——《敏捷软件开发》第11章

可见,依赖倒置的本质是依赖抽象,这与依赖注入的本质依赖容器,是两回事。

换句话说,如果Java没有接口、多态,依赖倒置就无从谈起。

而依赖注入依然可以存在,只要有一个注册表(《企业应用架构模式》第18章第5节)定义bean,利用反射来实例化并装配bean,有个容器容纳它们即可。

2.IoC(控制反转)与DI(依赖注入)是一样的吗?

IoC主要的实现方式有两种:依赖查找,依赖注入。(128页)

依赖注入是一种更可取的方式。(130页)

——《EXPERT ONE ON ONE J2EE DEVELOPMENT WITHOUT EJB》第6章

流行的「Martin Fowler将IoC改名为DI」的说法,Martin Fowler的原文在这里:

Inversion of Control Containers and the Dependency Injection pattern

As a result I think we need a more specific name for this pattern. Inversion of Control is too generic a term, and thus people find it confusing. As a result with a lot of discussion with various IoC advocates we settled on the name Dependency Injection.

大意是

已经存在某种模式,该模式被称为IoC,但IoC太普遍,任何框架都IoC,为了让表意更明确,决定用DI来精确指称那个模式。

意思大概就是

IoC ioc = the_pattern;
DI di = (DI)ioc;

显然,说the_pattern是IoC或DI都行,多态。但严格说IoC.class == DI.class肯定不为真,两者还是有区别,是 is-a 的关系。

不过正如不少人把Service和ServiceImpl分开,但Service事实上永远只有一个ServiceImpl实现一样,IoC虽然理论上还有其他实现,但DI过于主流,以至于混用了。

3.IoC(控制反转)的意义:

文中虽然说的是IoC,但可以确定在说DI。

在项目中应用DI,你会发现你的代码会变得异常简单并且更容易理解和测试。

——《Spring实战》第1章

另外说说不限于DI的IoC,你的代码不再被直接调用,而是被框架代码调用,所以说框架与类库的区别在于控制反转( 好莱坞原则,don't call me, i'll call you )。

往大了说,http请求不由你的Servlet/Filter直接处理,而是由Struts/Spring MVC的Servlet/Filter处理,再分配给你的组件,这也算IoC。

往小了说,操作数据库不再由你直接写jdbc的一大堆try嵌套,而是把固定的部分抽到JdbcTemplate中,你只负责写局部代码,然后由框架调你的局部代码,这也算IoC。

前一种,也就是前端控制器模式(《企业应用架构模式》第14章第3节),后一种,也就是模板方法模式(《设计模式》第5章第10节)。当然,除此之外还有很多。

所以说,IoC的好处,也就是框架的好处。

框架是一组程序的集合,包含了一系列的最佳实践,作用是解决某个领域的问题。

——《Struts2技术内幕》第2章

我认为,这就是控制反转的意义。

这说得很对,但把框架换成类库也适用。

关于框架的好处,在stackoverflow上一个问题下的答案我很喜欢:

What is the difference between a framework and a library?

大意是:

框架提供了骨架,你只要提供肉就可以了,你的肉在骨架中被调用。

我认为,这就是控制反转的意义。

框架提供了骨架(通用代码),你提供肉(业务逻辑)就行了。

你的肉在骨架中被调用(如web容器先调用框架,框架再调用你的代码,而不是你的代码直接被web容器调用)。

4.讲一下你对 IoC (依赖注入) 的理解:

首先,IoC(Inverse of Control,控制反转)在其他语言中也有应用,并非 Spring 特有,它是一种设计思想,基本概念就是将原本在程序中手动创建对象的控制权,交由 Spring 框架来管理。IoC 具体的实现方式是依赖注入。

简单的说之前我们在代码中创建一个对象是通过 new 关键字,而使用了 Spring 之后,我们不在需要自己去 new 一个对象了,而是直接通过容器里面去取出来,再将其自动注入到我们需要的对象之中,也就说创建对象的控制权不在我们程序员手上了,全部交由 Spring 进行管理。

交给 Spring 管理的也称为 Bean,所有的 Bean 都被存储在一个 Map 集合中,这个 Map 集合也称为 IoC 容器。

将对象之间的相互依赖关系交给 IoC 容器来管理,并由 IoC 容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。IoC 容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。

比如说,在实际项目中一个 Service 类可能有几百甚至上千个类作为它的底层,假如我们需要实例化这个 Service,你可能每次都要搞清这个 Service 所有底层类的构造函数,这显然过于繁琐。如果利用 IoC 的话,你只需要配置好,然后在需要的地方引用就行了,这大大增加了项目的可维护性且降低了开发难度。

寄语

    有人在奔跑,有人在睡觉,有人在感恩,有人在抱怨,有目标的睡不着,没目标的睡不醒,努力才是人生应有的态度,睁开眼就是新的开始。

本站文章主要用于个人学习记录,可能对您有所帮助,仅供参考!

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!