详解Spring之控制反转和依赖注入

最近在学习Spring相关的知识,谨以此文记录自己对本部分知识的学习。因此文中难免存在纰漏,希望各位大佬莫怪,如您愿意对此指点一二,那就在此谢过了。非常愿意再次与各位交流!
Ioc(Inverse of Control),即我们常听到的控制反转,是Spring容器的内核,AOP、声明式事务等功能都是在此基础上才能够繁衍生息、开花结果的。对于初学者来说,此概念却并不是那么易于理解的。
在这里引用陈雄华等编著的Spring4.x中的例子加以改编进行说明
(注:精通Spring4.x企业级应用开发这本书对于Spring4.x原理的讲解充实而又易懂,推荐有兴趣可以读一读,评论私聊获取本书资源)。
相信大家对钢铁侠这个角色并不陌生,电影《钢铁侠1》中Iron Man的扮演者小罗伯特唐尼,在山洞中完成了初代钢铁侠的设计建造。
我们就通过java语言来编写这一剧本,借此帮助大家理解IoC的概念。
本片最后的新闻发布会上,有记者问道:“谁才是钢铁侠?”,玩世不恭、骄傲自满的Tony Stark霸气的说出了那句经典台词:“ I am Iron Man!”

在这里插入图片描述然而大家可能都不一定清楚的是在电影选角的最初,导演是想邀请阿汤哥来演这部戏的男主角,但是阿汤哥却以我不适合这个角色而婉言推掉了邀约。后来的事情我们就在清楚不过了,小罗伯特唐尼在试镜的时候淋漓尽致的体现了剧中Tony特性格特点。最终被确定为钢铁侠的饰演者。
可能说了这么多,有好多人就看不下去了,说你这在讲电影呢,别着急,精彩马上就到:
先看一段代码:

public class IronMan1{
    
    
	public void newsConference(){
    
    
		//演员直接侵入剧本
		TomCruise tc = new TomCruise();
		tc.responce("I am Iron Man");
	}
}

通过上述的代码,我们可以发现上面的剧本和演员直接耦合在了一起,根据演员来创作电影(这没有道理啊!)。如果是这样的话,我们在看电影的时候会不会有一种错觉:什么?拯救世界的特工Ethon Hunt变身成为了钢铁侠,是不是感觉有点突兀,如果是这样的话那么这部电影可能就不会取得这么大的成就,也就不会有了后来的漫威宇宙了!!


(也挺帅的哈!但是不是缺少了些许眉宇间的霸气和混不吝的味道!哈哈)
回归正题:
我们可以看出来在上述的代码中,演员和角色之间的联系太过紧密,这样根据演员创作出来的剧本可能就会抑制了了编剧创作力!
一个优秀的编剧在创作时应该按照自己的灵感围绕剧本中的角色来展开,而不是已与演员创作剧本。再按照剧本中的角色来选择合适的演员才是正道!
这时候我们是不是清楚应该位剧本的主角设定一个接口:

public class IronMan1{
    
    
	public void newsConference(){
    
    
		//引入钢铁侠角色的接口
		IronMan im = new actor()//通过接口引入剧情
		im.responce("I am IronMan!");
	}
}

这样是不是就降低了剧本中IronMan这个角色和演员之间的联系程度。
但是还是存在问题:这部电影还是依赖于actor这个类。那么如何做才能让剧本的创作仅依赖于角色呢?来看下面这段代码:
1:构造函数注入:

public class IronMan1{
    
    
	private IronMan ironman;
	//注入IronMan的具体饰演者,
	public IronMan1(IronMan ironman){
    
    
		this.ironman = ironman;
	}
	public void responce(){
    
    
		ironman.responce("I am IronMan!");
	}
}
public class Director{
    
    
	public void director(){
    
    
		//指定角色的饰演者,IronMan为角色名
		IronMan im = new RobertDowneyJr();
		//具体饰演者开始演戏
		IronMan1 ironman1 = new IronMan1(im);
		ironman1.responce();
	}
}
		

我们发现,通过构造函数注入这种方式:剧本只提供台词和角色,由导演来选取具体的饰演者,饰演者完成相应的表演。
这样来看剧本、演员之间的关系就通过Director这一职务完成解耦,由导演负责根据剧本来筛选演员,并协调剧本、角色、演员三者之间的关系。
导演就像中间的大齿轮一样,安排演员饰演具体的角色::在这里插入图片描述
现在我们来讨论一下IoC是什么?
IoC(Inverse of Control),控制反转:就此案例来说即为选择IornMan演员的控制权从剧本中转移到了导演的手中。
【行话:某一接口的具体实现类的选择控制权从调用类中移除,转交给第三方容器来实现,即由Spring借由Bean配置来实现控制。】
还是有点晦涩难懂哈,其实用上述最后一段代码中的行话可能更易于理解一些:即依赖注入(DI:Dependency Injection)。
最初剧本对演员是有依赖的,如果最初按照阿汤哥来创作钢铁侠,是不是可能就没有后来钢铁侠的火爆程度了。这就说明现有的电影产业是成熟科学的:它通过导演这个第三方来移除剧本角色对某个具体演员的依赖。让导演来根据剧本选取演员的过程就是将演员注入到这部电影塑造角色的过程。
【行话:让调用类对某一接口的实现类的依赖关系由第三方(容器或者协作类)注入,移除调用类对某一接口实现类的依赖。】
实际上依赖注入共有三种类型:分别是构造函数注入、属性注入和接口注入。Spring支持构造函数注入和属性注入。
下面我们来说一说另外两种注入方式:
2、属性注入(即Setter方法注入):

public class IronMan1{
    
    
	private IronMan ironman;
	//属性注入方法
	public void setIronMan(IronMan ironman){
    
    
		this.ironman = ironman;
	}
	public void responce(){
    
    
		ironman.responce("I am Iron Man");
	}
}
public class Director{
    
    
	public void direct(){
    
    
		IronMan1 ironman1 = new IronMan1();
		//调用属性注入方法
		ironman im = new RobertDowneyJr();
		ironman1.setIronMan(im);
		ironman1.responce();
	}
}

但虽然TonyStark是电影的主角,但可能不是每时每刻都需要他来工作,这种情况就体现出属性注入的特点:实例化剧本时并未调用具体的饰演者,在实例化IronMan1之后,需要他出场时才调用setIronMan方法将RobertDowneyJr注入电影中。按照此方法可以为其他角色如Pepper提供注入方法,这样导演就可以根据拍摄时段让相应的演员就位而不是都到剧组中等待拍摄。
3、接口注入:
【行话:将调用类所有依赖注入的方法抽取到一个接口中,调用类实现该接口提供相应的注入方法。】
首先我们必须声明一个ActorArrangable接口:

public interfave ActorArrangable{
    
    
	void injectIronMan(IronMan ironman);
}
//IronMan1通过调用该接口提供具体类的实现
public IronMan1 implements ActorArranable{
    
    
	private IronMan ironman;
	//实现接口方法
	public  void injectIronMan(IronMan ironman){
    
    
		this.ironman = ironman;
	}
	public void resopnce(){
    
    
		ironman.responce("I am Iron Man!");
	}
}
//Director 通过ActorArrangeble的injectIronMan()方法来完成饰演者的注入
public class Director{
    
    
	public void dirct(){
    
    
		IronMan1 ironman1 = new IronMan1();
		IronMan ironman = new RobertDowneyJr();
		ironman1.injectIronMan(ironman);
		ironman1.responce
	}
}

接口注入需要额外声明一个接口,增加类的数目,且其效果和属性注入并无本质区别,因此我们并不怎么使用此方式啦。
到此我们就完成了对IoC和DI的初步认识了。接下来我们做一个总结:
控制反转和依赖注入其实是对同一技术的两种不同角度的描述方式:
IoC侧重于从思想层面去解释该技术,而DI侧重于从技术实现的角度来解释该技术。
由第三方容器去把所有的对象粘合在一起发挥作用,使对象之间彼此失去联系,从而达到解耦的目的。

(如果你觉得写的还不错,欢迎你点赞分享评论o!,我们一起交流一起进步!)
(欢迎您持续关注我的浅谈Spring系列!o!)

猜你喜欢

转载自blog.csdn.net/qq_40096391/article/details/105588745
今日推荐