请选择 进入手机版 | 继续访问电脑版

Spring IoC原理详解:皇帝不急太监急

[复制链接]
发表于 2018-1-3 09:45:28 |显示全部楼层

    有点标题党了。。。

    在学习Spring的开发过程中,IoC和Aop是我们必须要知道的知识 也是面试过程中会经常问到的问题 那么什么什么Ioc呢?


     1.定义

      IoC是一种模式。IoC(Inversion of Control)中文译为控制反转(即“不用你找,我来提供给你”)。控制反转意味着在系统开发过程中,设计的类将交由容器(spring中是通过applicationContext.xml控制的)去控制,而不是在类的内部去控制,类与类之间的关系将交由容器处理,一个类在需要调用另一个类时,只要调用另一个类在容器中注册的名字就可以得到这个类的实例,与传统的编程方式有了很大的不同。Martin Fowler在他的一篇文章中给IoC起了一个更为直观的名字:依赖注射DI(Dependency Injection)。
2.引入IoC

       在设计模式中,我们已经习惯一种思维编程方式:Interface Driven Design 接口驱动,接口驱动有很多好处,可以提供不同灵活的子类实现,增加代码稳定和健壮性等等,但是接口一定是需要实现的,也就是如下语句迟早要执行:InterfaceA a = new InterfaceAImp();  InterfaceAImp是接口InterfaceA的一个子类,IoC模式可以延缓接口的实现,根据需要实现,有个比喻:接口如同空的模型套,在必要时,需要向模型套注射石膏,这样才能成为一个模型实体,因此,我们将人为控制接口的实现成为注射(而工厂模式DAOFactory实际是返回的new InterfaceAImp(),即接口的实现类,所以工厂模式可理解为统一注入所有石膏,然后再调用)。
IoC模式是解决调用者和被调用者之间的一种关系,上述InterfaceA实现语句表明当前是在调用被调用者(即InterfaceAImp),由于被调用者名称写入了调用者的代码中,这产生了一个接口实现的原罪:彼此联系,调用者和被调用者有紧密联系,在UML中是用依赖(Dependency)表示。但是这种依赖在分离关注的思维下是不可忍耐的,必须切割,实现调用者和被调用者解耦,新的Ioc模式依赖注射(Dependency Injection)模式由此产生了,也就是将依赖先剥离,然后在适当时候再注射进入。
在Spring中,applicationContext.xml实际就是一个大工厂(这个大工厂的出现,免去了我们针对多个接口,需要定义多个工厂的烦恼);此外,与传统工厂不同,applicationContext.xml是基于IoC的工厂,是更为解耦合的工厂。
3.举例(网上选录)
1)就好比一个皇帝和太监。有一天皇帝想幸某个美女,于是跟太监说,今夜我要宠幸美女。皇帝往往不会告诉太监,今晚几点会回宫,会回哪张龙床,他只会告诉太监他要哪位美女,其它一切都交由太监去安排,到了晚上皇帝回宫时,自然会有美女出现在皇帝的龙床上,这就是控制反转,而把美女送到皇帝的寝宫里面去就是注射,太监就是是框架里面的注射控制器类BeanFactory(在Spring中, 太监相当于applicationContext.xml),负责找到美女并送到龙床上去,整个后宫可以看成是Spring框架,美女就是Spring控制下的接口实现(eg: JavaBean)。
而传统的模式就是一个饥渴男去找小姐出台,找领班,帮助给介绍一个云云,于是领班就开始给他张罗介绍一个合适的给他,完事后,再把小姐还给领班,下次再来。这个过程中,领班就是查询上下文Context(也就是一个负责提供小姐的工厂),领班的一个职能就是给客户找到他们所要的小姐,这就是lookup()方法,领班手中的小姐名录就是工厂类中的各个接口子类,也可以说是JNDI(Java Naming and Directory Interface)。小姐就是接口子类的实现Impl,饥渴男是客户端,青楼是Web容器。
看到区别了么?饥渴男去找小姐出台很麻烦,不仅得找,用完后还得把小姐给还回去,而皇帝爽翻了,什么都不用管,交给太监去处理,控制权转移到太监手中去了,而不是皇帝,必要时候由太监给注射进去就可以了。这就是Spring的美妙中的IoC的美妙之处。
2)设计Girl类和Boy类,其中Girl有kiss()方法,即Girl想要kiss()一个Boy。那么,我们的问题是,Girl如何能够认识这个Boy?在我们中国,常见的MM与GG的认识方式有以下几种:(1)青梅竹马;(2)亲友介绍;(3)父母包办。那么哪一种才是最好呢?
ioc1.png


这就是IOC,将对象的创建(青梅竹马模式)和获取(亲友介绍, 即工厂模式)提取到外部。由外部容器提供需要的组件。好莱坞有句名言:"Do not call us, we will call you.", 意思就是:"You, girl, do not call the boy. We will feed you a boy."
面向接口编程(也可以理解为面向抽象编程)是面向对象的核心。一般来说,组件应该分为两部分,即Service(所提供功能的声明)和ServiceImpl(Service的实现)。面向接口好处是:多种实现可以任意切换,防止"everything depends on everything"问题(即具体依赖于具体)。所以,我们的Boy应该是实现Kissable接口。这样一旦Girl不想kiss可恶的Boy的话,还可以kiss可爱的kitty和慈祥的grandmother。下面更进一步看各种框架下Girl得到Boy的不同方式:

ioc2.png



您需要登录后才可以回帖 登录 | 立即注册

Archiver|手机版|沙漏笔记

GMT+8, 2020-1-19 21:30 , Processed in 0.123750 second(s), 24 queries .

Powered by Discuz! X2.5

© 2001-2012 Comsenz Inc.

Copyright © 2015-2018 xuejava网 / 鲁ICP备17054568号-1
回顶部