作者
:学Java的冬瓜
博客主页
:☀冬瓜的主页
专栏
:【Framework】
主要内容
:什么是spring?IoC容器是什么?如何使代码解耦合?IoC的核心原理,IoC的优点。依赖注入/对象装配/DI。
Spring:包含了 众多工具方法 的
IoC
容器。
IoC 全称 Inversion of Control,翻译为控制反转。因此IoC容器就是控制反转的容器。那啥是 控制反转?Spring框架管理Bean的创建工作。即
由用户管理Bean变为框架管理Bean
① 举个例子:接下来我们举个例子,并使用代码来感受啥是个IoC(控制反转),有什么好处:
比如建造一个房子,粗略的看,首先需要打地基,然后砌砖,最后挂房梁瓦片等。如果用代码实现这样一个粗略的过程,看下面代码:
//测试类
public class Test {
public static void main(String[] args) {
House house = new House();
house.init();
}
}
//房
public class House {
public void init(){
// 创建房子 依赖于挂房梁等操作
Beam beam = new Beam();
beam.init();
System.out.println("House: House create");
}
}
//房梁
public class Beam {
private String material;//(杉木)
public void init(){
// 挂房梁等 依赖于 砌好砖
Brick brick = new Brick();
brick.init();
System.out.println("Bean: 房梁木用 " + this.material);
}
}
//砖
public class Brick {
private String redBrick;//红砖
public void init(){
// 砌砖 依赖于 已经打好地基
Foundation foundation = new Foundation();
foundation.init();
System.out.println("Brick: 砌砖用 " + this.redBrick);
}
}
//地基
public class Foundation {
private String rebar;//钢筋
private String cement;//水泥
public void init(){
System.out.println("Foundation: 打地基用 " + this.rebar +" "+ this.cement);
}
}
② 理解代码:上面的代码中,测试类中的main方法运行后,会创建一个空House对象,再进行House对象的初始化;在House对象初始化时,会创建一个空的Beam对象,然后进行beam对象的初始化(house依赖于beam,房子依赖于房梁);beam初始化时,会创建Brick对象,再进行brick对象的初始化(beam依赖于brick,房梁依赖于砌好砖);brick对象初始化时,会创建Foundation对象,并进行foundation对象的初始化。
简单来说,要想建房子,得先挂好房梁,要想挂房梁,得先砌好砖,要想砌砖,得先打好地基,这就是一个逐层调用进行初始化的过程,最终建好一个房子。但是这样操作会引入一个很致命的问题:代码耦合度非常高!
③ 问题:这样互相依赖的过程,如果底层的类发生改变,上层的类得相应改变。在上面代码中,我使用钢筋水泥打地基,用红砖来砌砖,用杉木来做房梁木,在每个类的调用init方法时将所需参数传进去,进行材料的初始化(我这里没弄,所以都是null)。那么理解到这里我们可以想一个问题,如果我不再使用红砖来砌砖,而是使用水泥砖了,或者我需要制定特定尺寸的砖,那么Brick类的属性就需要修改调整。这样在上层调用中(beam)也需要修改,在Beam类的init方法中,创建了Brick类,并使用brick.init(参数)这个方法进行砌砖的初始化,那么这里也是需要修改的,如果上层还有给brick传参的方法,那也还需要改,所以这样操作,代码耦合度会非常高。
④ IoC和Spring:怎么才能降低耦合,减少修改的成本?因为上述代码出现高耦合的原因:在当前类中的方法中,创建当前类所依赖的类的对象并逐层调用初始化对象,或者上层的代码给底层的类的属性传参数。
法一:当存在依赖关系时,在当前类的方法中不再自己创建和销毁所依赖的对象,而是让调用者传一个依赖对象给当前类(当前类需要一个成员变量是它所依赖的类),如果这个类还存在其他属性,也由调用者提供参数(这样就可保证,在我需要修改某一个类的成员或者类型时,其他类不需要做修改,即实现解耦合)。
法二:那如果我不让它逐层调用,而是统一交给一个工具去创建对象并初始化并管理对象呢?这就是控制反转,Spring就是管理对象的这样一个容器。
⑤ Spring:在管理方面,Spring是一个 IoC容器,它可以管理对象,包括创建销毁对象等。在操作方面,又因为是个 IoC容器,因此可以把对象存进Spring或者从Spring中获取对象。
//测试类
package demo2;
public class Test {
//测试传对象 解耦合代码
public static void main(String[] args) {
Foundation foundation = new Foundation("xx号钢筋", "xx号水泥");
Brick brick = new Brick(foundation, "xx号红砖");
Beam beam = new Beam(brick, "杉木");
House house = new House(beam);
house.init();
}
}
//House类
package demo2;
public class House {
private Beam beam;
public House(Beam beam){
this.beam = beam;
}
public void init(){
// 创建房子 依赖于挂房梁等操作
beam.init();
System.out.println("house: 房子建成");
}
}
//Beam类
package demo2;
public class Beam {
private Brick brick;
private String material;
public Beam(Brick brick, String material){
this.brick = brick;
this.material = material;
}
public void init(){
// 挂房梁等 依赖于 砌好砖
brick.init();
System.out.println("Bean: 房梁木用 " + this.material);
}
}
//Brick类
package demo2;
public class Brick {
private Foundation foundation;
private String redBrick;//红砖
public Brick(Foundation foundation, String redBrick){
// 砌砖 依赖于 已经打好地基
this.foundation = foundation;
this.redBrick = redBrick;//新增
}
public void init(){
this.foundation.init();
System.out.println("Brick: 砌砖用 " + this.redBrick);
}
}
//Foundation类
package demo2;
public class Foundation {
private String rebar;//钢筋
private String cement;//水泥
public Foundation(String rebar, String cement){
this.rebar = rebar;
this.cement = cement;
}
public void init(){
System.out.println("Foundation: 打地基用 " + this.rebar +" "+ this.cement);
}
}
具体操作,看后面的博客
存对象 取对象
①
解耦合
②使用方便
(不再需要手动创建对象)
③更加高效
(默认情况,使用相同类只需要创建一个对象)
IoC,(Inversion of Control 控制反转)是一种设计原则,指的是将对象的创建和依赖关系交给容器来完成而不是由对象自己管理依赖对象。
DI,(Dependency Injection 依赖注入),是IoC的一种具体的实现方式,它是通过将依赖对象注入到对象中来实现对象之间的解耦。
简而言之,IoC是一种思想,而DI是IoC的一种具体实现方式
。
补充1:实现IoC除了DI之外,还需要控制反转容器(在Spring中就是Spring容器)和配置信息(xml文件,描述对象和依赖关系的元数据)。
补充2:① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩(在这里列出这种序号,需要的自取)。