对Spring控制反转和依赖注入的理解----生动形象(IOC、DI)

1. IOC 控制反转

IOC : inversion of control 控制反转 ----实例化的一个过程
实例化的主动权交给Spring ,以配置的形式来进行,将实例化的对象放入Spring容器中。即,
通过Spring容器管理Java类的对象,而不是在Java类中new一个对象。

好莱坞法则:“别找我们,我们找你”
为什么叫控制反转?顾名思义,将寻找(实例化)对象的控制权转交给容器,而不是自己控制这个对象。

没理解?别着急!往下看。
提前告诉你:
别找我们 ,别傻乎乎地在自己的类里面引入另一个类,耦合度高,牵一发动全身~
我们找你,你都不找我了,怎么用我们啊,只能我们自己上门了。这个上门可不是在你那打地基盖房子,而是我们携家带口揣着户口本房产证上门,就是说,该有的我们都有,我们是对象,不用new, 给你注入你用就行。

2. DI 依赖注入

DI:Dependency Injection
目的:保持松散耦合

2.1 常规方式

骑士为了展现自己的冒险精神,自己new 了一个Quest对象,然后对此对象进行操作。骑士打败了坏蛋Bully,他觉得自己升级了,“老子天下第一”,我要去杀死恶龙。然而骑士发现,我TM去哪找恶龙啊?好,我千辛万苦在苦逼程序员手动引入的前提下找到了恶龙类,new 一个外部的恶龙类才能杀龙,好麻烦啊。

初级骑士

// 骑士类
public class Knight {
    
    
	private Quest quest;
	public Knight() {
    
    
		this.quest = new Quest();
	}
	
	public void embark() {
    
    
		System.out.println("骑士将要做的事:");
		quest.killBully();
		
	}
}

冒险类1—坏蛋类

//冒险类1---坏蛋类
public class Quest1 {
    
    
	public String killBully() {
    
     //打败坏蛋
		return "kill Bully";
	}
}

升级后的骑士

好,作为骑士我现在可以屠龙了。感谢帮我引入恶龙类的新时代码农!码农啊,你是否产生了这样一个疑问:直接在Quest1—坏蛋类里加一个方法,让坏蛋骑着恶龙,我作为骑士,再引入一个屠龙的方法就行啊。码农再想,不对啊,这不就破坏了Java的封装性了吗?两个实体类合成一个,你是想直接打BOSS吗,不行!万一世界上还有什么青龙、白龙呢?

// 骑士类
public class Knight {
    
    
	private Quest1 quest1;
	private Quest2 quest2;
	public Knight() {
    
    
		this.quest1 = new Quest1();
		this.quest2 = new Quest2();
	}
	
	public void embark() {
    
    
		System.out.println("骑士将要做的事:");
		quest1.killBully();
		quest2.killDragon();
	}
}

冒险类2----恶龙类

//冒险类2
public class Quest2 {
    
    
	public String killDragon() {
    
     //屠龙
		return "kill dragon";
	}
}

2.2 头秃的骑士

骑士觉得老是靠程序员帮自己做事,面子挂不住。于是,有一天,骑士找了一个中介,也就是Spring容器,中介可以通过XML配置的形式,向骑士注入一系列信息。这下码农着急了,你这不开挂吗?码农想学习到这种技术,然后把骑士的生意抢回来!
那我就教你 “注入” !!
先给你灌输一个词汇:接口

升级后的探险

public interface QuestPro {
    
    
	public void embark();
}

坏蛋被探险

public class BullyImpl implements QuestPro {
    
    

	@Override
	public void embark() {
    
    
		System.out.println("kill bully");
	}

}

恶龙被探险

public class DragonImpl implements QuestPro {
    
    

	@Override
	public void embark() {
    
    
		System.out.println("kill dragon");
	}

}

最强骑士

public class KnightPro {
    
    
	private QuestPro questPro;
	public KnightPro(QuestPro questPro) {
    
    //QuestPro被注入进来
		this.questPro = questPro;
	}
	
	public void quest() {
    
    
		questPro.embark();
	}
}

骑士说!

加了接口就是注入了吗?并不是!码农啊,你想一想,是不是QuestPro被注入骑士类了,那谁来实例化这个QuestPro呢?
答案就是中介!通过XML配置给骑士注入一个对象,而不需要骑士自己去new。
骑士:确实不能自己new, 即使是实现了接口,那我自己new的时候,还需要new 两个对象!

QuestPro q1 = new BullyImpl();
QuestPro q2 = new DragonImpl();

这和不用接口什么区别!还是得靠中介注入啊。直接注入对象,你注入啥我就用啥,来者不拒。

public KnightPro(QuestPro questPro) {
    
    //QuestPro被注入进来
		this.questPro = questPro;
	}

3. 总结

码农明白了!如果骑士还想继续升级,无论是怪兽还是奥特曼,只要实现了QuestPro接口;中介注入给骑士一个对象,那骑士就可以出手了,而且自己内部还不用变动。
扛着长枪短炮的去冒险太麻烦了,轻装上阵才最强!

程序的整个思想是控制反转,具体实现采用依赖注入!
专业术语表示:
控制反转:实例化的主动权交给Spring ,以配置的形式来进行,将实例化的对象放入Spring容器中。
依赖注入:
什么是依赖?冒险类依赖于骑士类,没有骑士哪来的冒险!
什么是注入?就是不用自己实例化对象,用到的对象都是外界传入的。

4. 再总结

依赖注入

以下文字来源于菜鸟教程

Spring框架的核心功能有两个:

  1. Spring容器作为超级大工厂,负责创建、管理所有的Java对象,这些Java对象被称为Bean。
  2. Spring容器管理容器中Bean之间的依赖关系,Spring使用一种被称为"依赖注入"的方式来管理Bean之间的依赖关系。

使用依赖注入,不仅可以为Bean注入普通的属性值,还可以注入其他Bean的引用。依赖注入是一种优秀的解耦方式,其可以让Bean以配置文件组织在一起,而不是以硬编码的方式耦合在一起。
理解依赖注入

Rod Johnson是第一个高度重视以配置文件来管理Java实例的协作关系的人,他给这种方式起了一个名字:控制反转(Inverse of Control,IoC)。后来Martine Fowler为这种方式起了另一个名称:依赖注入(Dependency Injection),因此不管是依赖注入,还是控制反转,其含义完全相同。当某个Java对象(调用者)需要调用另一个Java对象(被依赖对象)的方法时,在传统模式下通常有两种做法:

原始做法: 调用者主动创建被依赖对象,然后再调用被依赖对象的方法。
简单工厂模式: 调用者先找到被依赖对象的工厂,然后主动通过工厂去获取被依赖对象,最后再调用被依赖对象的方法。

注意上面的主动二字,这必然会导致调用者与被依赖对象实现类的硬编码耦合,非常不利于项目升级的维护。使用Spring框架之后,调用者无需主动获取被依赖对象,调用者只要被动接受Spring容器为调用者的成员变量赋值即可,由此可见,使用Spring后,调用者获取被依赖对象的方式由原来的主动获取,变成了被动接受——所以Rod Johnson称之为控制反转。

另外从Spring容器的角度来看,Spring容器负责将被依赖对象赋值给调用者的成员变量——相当于为调用者注入它依赖的实例,因此Martine Fowler称之为依赖注入。

Spring 最认同的技术是控制反转的依赖注入(DI)模式。控制反转(loC)是一个通用的概念,它可以用许多不同的方式去表达,依赖注入仅仅是控制反转的一个具体的例子。W3Cschool的解释

5. 再再总结

上面菜鸟教程说依赖注入和控制反转完全一致。我认为二者只是侧重点不同而已。
控制反转侧重于向Spring容器加入实例,即加入Bean,配置XML,

猜你喜欢

转载自blog.csdn.net/qq_43709785/article/details/119953970