【Spring IoC】容器和IoC介绍以及IoC程序开发的优势

文章目录

在前面中,我们学习了 Spring Boot 和 Spring MVC 的开发,可以完成一些基本功能的开发了,但是什么是 Spring 呢?Spring,Spring Boot,SpringMVC 又有什么关系呢?

Spring 是什么

通过前面的学习,我们知道了 Spring 是一个开源框架,他让我们的开发更加简单。他支持广泛的应用场景,有着活跃而庞大的社区,这也是 Spring 能后长久不衰的原因

但是这个概念相对来说是比较抽象的。我们用一句更具体的话来概括 Spring,那就是:Spring 是包含了众多工具方法的 IoC 容器

  • 那问题来了,什么是容器?什么是 IoC 容器?

什么是容器

容器是用来容纳某种物品的(基本)装置。生活中的水杯,垃圾桶,冰箱等等这些都是容器。

我们想象,之前的内容中我们接触到了哪些容器?

  • List/Map:数据存储容器
  • Tomcat:Web 容器

什么是 IoC

IoCSpring 的核心思想,也是常见的面试题。其实我们在前面已经使用过了 IoC,在类上面添加 @RestController 注解,就是把这个对象交给 Spring 管理,Spring 框架启动时就会加载该类。把对象交给 Spring 管理,就是 IoC 思想


IoC:Inversion of Control(控制反转),也就是说 Spring 是一个"控制反转"的容器

什么是控制反转呢?

也就是控制权反转,获得依赖对象的过程被反转了,也就是说,当需要某个对象时,传统开发模式中需要自己通过 new 创建对象,现在不需要再及你选哪个创建,把创建对象的任务交给容器,程序中只需要依赖注入(Dependency Injection,DI)就可以了,这个容器称为:IoC 容器,Spring 是一个 IoC 容器,所以有时 Spring 也称为 Spring 容器

控制反转是一种思想,在生活中也是处处体现

比如自动驾驶,传统驾驶方式,车辆的横向和纵向驾驶控制权由驾驶员来控制,现在交给了驾驶自动化系统来控制,可也是控制反转思想在生活动的实现

比如招聘,企业的员工招聘,入职,解雇等控制权,由老板转交给 HR 来处理

IoC 介绍

需求:造一台车

传统程序开发

我们的实现思路是这样的:

先设计轮子(Tire),然后根据轮子的大小设计底盘(Bottom),接着根据底盘设计车身(Framework),最后根据车身设计好整个汽车(Car)。这里就出现了一个"依赖"关系:汽车依赖车身,车身依赖底盘,底盘依赖轮子

java 复制代码
public class NewCarExample {
	public static void main(String[] args) {
		Car car = new Car();
		car.run();	
	}
	
	/**
	 *汽车对象
	 */
	static class Car {  
	    private Framework framework;  
	    
	    public Car() {  
	        framework = new Framework();  
	        System.out.println("framework init...");  
	    } 
	    public void run() {  
	        System.out.println("car run...");  
	    }  
	}


	/**
	 *车身类
	 */
	 static class Framework {  
	    private Bottom bottom;  
	    
	    public Framework() {  
	        bottom = new Bottom();  
	        System.out.println("bottom init...");  
	    }  
	}	


	/**
 	*底盘类
 	*/
 	static class Bottom {  
	    private Tire tire;  
	  
	    public Bottom() {  
	        tire = new Tire();  
	        System.out.println("tire init...");  
	    }  
	}

	/**
 	*轮胎类
 	*/
 	public class Tire {  
	    private int size = 21;  
	  
	    public Tire() {  
	        System.out.println("tire size:" +size);  
	    }  
	}
}

这样的设计看起来没问题,但是可维护性却很低.

接下来需求有了变更: 随着对的⻋的需求量越来越⼤, 个性化需求也会越来越多,我们需要加⼯多种尺

⼨的轮胎.

那这个时候就要对上⾯的程序进⾏修改了,修改后的代码如下所⽰

修改之后, 其他调⽤程序也会报错, 我们需要继续修改


完整代码如下:

java 复制代码
public class NewCarExample {
	public static void main(String[] args) {
		Car car = new Car(21);
		car.run();	
	}
	
	/**
	 *汽车对象
	 */
	static class Car {  
	    private Framework framework;  
	    
	    public Car(int size) {  
	        framework = new Framework(size);  
	        System.out.println("framework init...");  
	    } 
	    public void run() {  
	        System.out.println("car run...");  
	    }  
	}


	/**
	 *车身类
	 */
	 static class Framework {  
	    private Bottom bottom;  
	    
	    public Framework(int size) {  
	        bottom = new Bottom(size);  
	        System.out.println("bottom init...");  
	    }  
	}	


	/**
 	*底盘类
 	*/
 	static class Bottom {  
	    private Tire tire;  
	  
	    public Bottom(int size) {  
	        tire = new Tire(size);  
	        System.out.println("tire init...");  
	    }  
	}

	/**
 	*轮胎类
 	*/
 	public class Tire {  
	    private int size = 21;  
	  
	    public Tire(int size) {  
	    	this.size = size;
	        System.out.println("tire size:" +size);  
	    }  
	}
}

从以上代码可以看出,以上程序的问题是:当最底层代码改动之后,整个调⽤链上的所有代码都需要
修改.

程序的耦合度⾮常⾼(修改⼀处代码, 影响其他处的代码修改)

解决方法

在上⾯的程序中, 我们是根据轮⼦的尺⼨设计的底盘,轮⼦的尺⼨⼀改,底盘的设计就得修改. 同样因

为我们是根据底盘设计的⻋⾝,那么⻋⾝也得改,同理汽⻋设计也得改, 也就是整个设计⼏乎都得改

我们尝试换⼀种思路, 我们先设计汽⻋的⼤概样⼦,然后根据汽⻋的样⼦来设计⻋⾝,根据⻋⾝来设计底盘,最后根据底盘来设计轮⼦. 这时候,依赖关系就倒置过来了:轮⼦依赖底盘, 底盘依赖⻋⾝,⻋⾝依赖汽⻋

这就类似我们打造⼀辆完整的汽⻋, 如果所有的配件都是⾃⼰造,那么当客⼾需求发⽣改变的时候,

⽐如轮胎的尺⼨不再是原来的尺⼨了,那我们要⾃⼰动⼿来改了,但如果我们是把轮胎外包出去,那

么即使是轮胎的尺⼨发⽣变变了,我们只需要向代理⼯⼚下订单就⾏了,我们⾃⾝是不需要出⼒的.

如何来实现呢:

我们可以尝试不在每个类中⾃⼰创建下级类,如果⾃⼰创建下级类就会出现当下级类发⽣改变操作,

⾃⼰也要跟着修改.

此时,我们只需要将原来由⾃⼰创建的下级类,改为传递的⽅式(也就是注⼊的⽅式),因为我们不

需要在当前类中创建下级类了,所以下级类即使发⽣变化(创建或减少参数),当前类本⾝也⽆需修

  • 改任何代码,这样就完成了程序的解耦

IoC 程序开发

基于以上思路,我们把调用汽车的程序实例改造一下,把创建子类的方式,改为注入传递的方式,具体实现代码如下:

java 复制代码
public class NewCarExample {
	public static void main(String[] args) {
		Tire tire = new Tire(20);
		Bottom bottom = new Bottom(tire);
		Framework framework = new Framework(bottom);
		Car car = new Car(framewoek);
		car.run();	
	}
	
	/**
	 *汽车对象
	 */
	static class Car {  
	    private Framework framework;  
	    
	    public Car(Framework framework) {  
	        framework = new Framework();  
	        System.out.println("framework init...");  
	    } 
	    public void run() {  
	        System.out.println("car run...");  
	    }  
	}


	/**
	 *车身类
	 */
	 static class Framework {  
	    private Bottom bottom;  
	    
	    public Framework(Bottom bottom) {  
	        bottom = new Bottom();  
	        System.out.println("bottom init...");  
	    }  
	}	


	/**
 	*底盘类
 	*/
 	static class Bottom {  
	    private Tire tire;  
	  
	    public Bottom(Tire tire) {  
	        tire = new Tire();  
	        System.out.println("tire init...");  
	    }  
	}

	/**
 	*轮胎类
 	*/
 	public class Tire {  
	    private int size = 21;  
	  
	    public Tire(int size) {  
	    	this.size = size;
	        System.out.println("tire size:" +size);  
	    }  
	}
}
  • 代码经过以上调整,⽆论底层类如何变化,整个调⽤链是不⽤做任何改变的,这样就完成了代码之间的解耦,从⽽实现了更加灵活、通⽤的程序设计了。

IoC 的优势

  • 在传统的代码中对象创建顺序是:Car -> Framework -> Bottom -> Tire
  • 改进之后解耦的代码的对象创建顺序是:Tire -> Bottom -> Framework -> Car

我们发现了⼀个规律,通⽤程序的实现代码,类的创建顺序是反的,传统代码是 Car 控制并创建了 FrameworkFramework 创建并创建了 Bottom,依次往下,⽽改进之后的控制权发⽣的反转,不再是使⽤⽅对象创建并控制依赖对象了,⽽是把依赖对象注⼊将当前对象中,依赖对象的控制权不再由当前类控制了.

这样的话, 即使依赖类发⽣任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是 IoC 的实现思想。

学到这⾥, 我们⼤概就知道了什么是控制反转了, 那什么是控制反转容器呢, 也就是 IoC 容器

这部分代码, 就是 IoC 容器做的⼯作.

从上⾯也可以看出来, IoC 容器具备以下优点:

  • 资源不由使⽤资源的双⽅管理,⽽由不使⽤资源的第三⽅管理,这可以带来很多好处。第⼀,资源集中管理 ,实现资源的可配置和易管理 。第⼆,降低 了使⽤资源双⽅的依赖程度,也就是我们说的耦合度
  1. 资源集中管理: IoC 容器会帮我们管理⼀些资源(对象等), 我们需要使⽤时, 只需要从 IoC 容器中去取

    就可以了

  2. 我们在创建实例的时候不需要了解其中的细节, 降低了使⽤资源双⽅的依赖程度, 也就是耦合度。Spring 就是⼀种 IoC 容器, 帮助我们来做了这些资源管理.

相关推荐
李慕婉学姐13 小时前
【开题答辩过程】以《基于JAVA的校园即时配送系统的设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·开发语言·数据库
奋进的芋圆15 小时前
Java 延时任务实现方案详解(适用于 Spring Boot 3)
java·spring boot·redis·rabbitmq
sxlishaobin15 小时前
设计模式之桥接模式
java·设计模式·桥接模式
model200515 小时前
alibaba linux3 系统盘网站迁移数据盘
java·服务器·前端
荒诞硬汉15 小时前
JavaBean相关补充
java·开发语言
提笔忘字的帝国15 小时前
【教程】macOS 如何完全卸载 Java 开发环境
java·开发语言·macos
2501_9418824816 小时前
从灰度发布到流量切分的互联网工程语法控制与多语言实现实践思路随笔分享
java·开发语言
華勳全栈16 小时前
两天开发完成智能体平台
java·spring·go
alonewolf_9916 小时前
Spring MVC重点功能底层源码深度解析
java·spring·mvc
沛沛老爹16 小时前
Java泛型擦除:原理、实践与应对策略
java·开发语言·人工智能·企业开发·发展趋势·技术原理