撸一撸Spring Framework-IoC-概述

Spring Framework中最核心的模块就是IoC容器(Inversion of Control,控制反转),其他模块如aop、aspectjs、Data Access等都在此基础上展开,我们就从IoC开始旅程 

关于IoC,spring官网给出的解释是这样的:

IoC is also known as dependency injection (DI). It is a process whereby objects define their dependencies (that is, the other objects they work with) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes or a mechanism such as the Service Locator pattern.

解释如下:

IoC也称为依赖注入(Dependeccy Injection,DI),注意,这二者是替代关系,并不是网上广泛传播的、极具迷惑性的"思想和实现"的关系,下文会对这点作出解释

考虑一个东西存在的意义,只需考虑有没有它的差异即可:若没有IoC,要在类中自行控制它的依赖项(也就是对象需要引用的其他对象)的实例化、初始化工作,这看似轻飘飘的两个词,实则暗示着大量重复且枯燥的编码工作。只需简单设想一下,成百上千个Controller、Service、repository等组件互相依赖,若要在类中自行创建、初始化这些依赖项,程序员表示不想写这么多new XX()、setXX();好在有IoC,只要在类中通过构造器参数、工厂方法参数、或者属性这些方式声明好他们的依赖项,其他事情交给IoC容器即可,IoC容器在构造bean时,会按照类声明的方式为其注入对应的依赖项。为了省去大量枯燥的工作,将对依赖项的控制权操作交给IoC容器,因此得名控制反转

由于"Inversion of Control"这个定义着实有点不够开门见山,业界曾进行了广泛的讨论,最终由Martin Fowler提出了使用"Dependeccy Injection"的概念来代替,前面关于IoC的解释也正是围绕着如何管理类的依赖项而来的,用"依赖注入"明显比"控制反转"更直接明了 

除了上述依赖项管理工作的考量外,IoC还涉及解耦、设计模式等内涵,关于这点,我直接引用《精通spring4.x》中的例子:

张之亮的贺岁大片《墨攻》中,有一段"城门叩问"的场景:刘德华饰演的角色墨者革离到达梁国都城下时,城上梁国守军问道:"来者何人?",刘德华回答:"墨者革离!"
现在考虑为这个剧本编写代码(MoAttack即为《墨攻》剧本):

1、直接使用演员编排剧本
public class MoAttack{
    public void cityGateAsk(){
         //演员直接侵入剧本
         LiuDeHua ldh=new LiuDeHua();
         ldh.responseAsk("墨者革离!");
    }
}

上述剧本中,饰者刘德华直接侵入脚本,使得剧本和演员直接耦合在一起。一个明智的编剧在剧情创作时应围绕故事的角色展开,而不应该考虑具体饰演者,这样才可能在剧本投拍时自由选择任何适合的演员,而非早早的绑定在一人身上

2、通过角色编排剧本
public class MoAttack{
    public void cityGateAsk(){
         //引入革离角色接口
         GeLi geli=new LiuDeHua();
         //通过接口展开剧情
         geli.responseAsk("墨者革离!");
    }
}

此时虽然引入了角色接口GeLi,但却使得MoAttack同时依赖于GeLi接口和LiuDeHua类,并没有达到剧本仅应该依赖于角色的目的,但角色必然需要具体的演员才能完成拍摄。因此引入导演

3、引入导演,管理剧本、角色、饰演者三者的协调关系
public class Director{
	public void direct(){
		//指定角色的饰演者
		GeLi geli=new LiuDeHua();
		//将具体饰演者注入剧本中
		MoAttack moAttack=new MoAttack(geli);
		moAttack.cityGateAsk();
	}
}
public class MoAttack{
	private GeLi geli;
	//不再关注具体饰演者
	public MoAttack(GeLi geli){
		this.geli=geli;
	}
	public void cityGateAsk(){
		geli.responseAsk("墨者革离!");
	}
}

例子中的Director充当的就是IoC容器的角色,它带来的好处不仅仅是帮MoAttack省去了依赖项的管理工作,还使它与具体饰演者解耦

以上就是IoC的好处了,例子中,MoAttack与具体饰演者的解耦利用了接口的多态性,因"革离"这个角色确实可能存在变更饰演者(具体实现)的情况,所以接口GeLi有其存在的必要性。那么请大家思考下,如今应用开发项目中,几乎每个Service都是类似于XXService+XXServiceImpl的组成,这里的每个XXService接口都有存在的必要性吗?

"You aren't gonna need it"(YAGNI)是极限编程(extreme programming,XP)中的一个原则,意思是除非真的有必要,否则不要添加。体现在这里就是:如果你不确定是否真的需要接口,那你很可能不需要。接口适用的场景包括:1.可能存在多种实现,通过接口的多态性实现调用方无感知的实现替换;2.模块间交互时,不希望其他模块了解过多细节。多数情况下,Service类并不存在替换实现的需要,并且由于逻辑简单,直接暴露出去也并无不可,接口应该基于抽象建模,简单的通过提升类中的公共方法来创建的接口,并没有太大意义

猜你喜欢

转载自blog.csdn.net/wb_snail/article/details/120998488