一:什么是Spring
Spring:是一个开源的Java框架,它提供了广泛的基础设施支持,用于构建Java应用程序。Spring框架的主要目标是简化Java应用程序的开发,提高代码的可维护性,并促进面向对象编程的最佳实践。总而言之,Spring是包含了众多工具方法的IoC容器
- 容器: 是用来容纳某种物品的基本装置
- List/Map:数据存储容器
- Tomcat:Web容器
- IoC: 是英文Inversion of Control的的缩写,中文含义为“控制反转”,也就是说Spring是一个控制反转的容器
二:理解Spring IoC
控制反转(IoC):是软件设计模式的一种,用于解决组件之间的依赖关系管理问题。在IoC模式中,控制权由应用程序代码转移到了一个容器或框架,它负责管理对象的创建、生命周期和依赖关系。这种反转控制的思想旨在降低组件之间的耦合度,提高代码的可维护性和可测试性。IoC核心思想包含用以下几个关键概念
- 依赖关系反转(Dependency Inversion): 这是IoC的基础。它强调高层模块不应该依赖于底层模块,而两者都应该依赖于抽象。这意味着应用程序组件应该依赖于接口或抽象类,而不是具体的实现类。这有助于降低组件之间的紧耦合
- 容器: IoC容器是一个负责管理对象的工厂,它负责创建、配置和维护应用程序中的各种对象。容器负责解析对象之间的依赖关系,并在需要时注入依赖
- 配置: IoC容器通常使用外部配置文件(如XML文件或注解)来描述对象之间的依赖关系和配置信息。这使得可以在不修改应用程序代码的情况下,更改对象的配置和行为
- 注入(Injection): IoC容器通过依赖注入将对象的依赖关系注入到对象中,而不是由对象自行创建或查找依赖。这有助于解耦和对象的创建和依赖解析过程
IoC的最常见实现之一是通过使用框架,如Spring框架,来实现依赖注入和控制反转。在Spring中,开发人员可以配置bean,并定义它们之间的依赖关系,然后Spring容器负责创建和管理这些bean,并自动注入它们的依赖关系。这大大简化了应用程序的开发和维护,提高了可扩展性和可测试性
为了能够更好的理解IoC,这里我们通过对比传统程序开发和IoC程序开发来进行说明
(1)传统程序开发
假设我们要构建一辆车(抽象类),这辆车非常简单,需要车身、底盘和轮胎三个部分,那么实现思路如下
具体来说
- 想要一辆车得先要车身
- 想要车身得先要底盘
- 想要底盘得先要轮胎
实现代码如下
public class CreateCar {
public static void main(String[] args) {
Car car = new Car();
car.init();
}
}
public class Car {
private Frame frame;
public Car() {
frame = new Frame();
}
public void init() {
// 车需要依赖车身
frame.init();
System.out.println("初始化车");
}
}
public class Frame {
private Bottom bottom;
public Frame() {
bottom = new Bottom();
}
public void init() {
// 车身需要依赖底盘
bottom.init();
System.out.println("初始化车身");
}
}
public class Bottom {
private Tire tire;
public Bottom() {
tire = new Tire();
}
public void init() {
// 底盘需要依赖轮胎
tire.init();
System.out.println("初始化底盘");
}
}
public class Tire {
private int size = 20;
public void init (){
System.out.println("初始化轮胎");
}
}
这种传统程序设计方法虽然符合人的逻辑思维,但是也存在着很大的弊端。主要体现在修改时极其不方便,牵一发而动全身,也就是耦合性太强。例如,如果需要对轮胎尺寸修改(或者对轮胎有更多的定制化需求,这里只是举了最简单的情形),就需要从最外面传入尺寸,所有代码都要修改
public class CreateCar {
public static void main(String[] args) {
int size = 100;
Car car = new Car(size);
car.init();
}
}
public class Car {
private Frame frame;
public Car(int size) {
frame = new Frame(size);
}
public void init() {
// 车需要依赖车身
frame.init();
System.out.println("初始化车");
}
}
public class Frame {
private Bottom bottom;
public Frame(int size) {
bottom = new Bottom(size);
}
public void init() {
// 车身需要依赖底盘
bottom.init();
System.out.println("初始化车身");
}
}
public class Bottom {
private Tire tire;
public Bottom(int size) {
tire = new Tire(size); // 修改
}
public void init() {
// 底盘需要依赖轮胎
tire.init();
System.out.println("初始化底盘");
}
}
public class Tire {
private int size = 20;
public Tire(int size) {
this.size = size; // 修改
}
public void init (){
System.out.println("初始化轮胎");
}
}
(2)控制反转程序开发
可以发现,如果某个类创建了下级类,那么当下级类修改时自己也会受到影响。因此我们可以将这种创建的方式修改为注入,只是声明我需要这样的类,而不创建它。关于这个下级类的生命周期又它自己掌管,这样的话就完成了程序的解耦。如此一来,即使下级类发生变化,也不会影响上级类,因为我只是需要这样一个类,你只需要创建好给我即可
实现代码如下
public class CreateCar {
public static void main(String[] args) {
// 造轮胎
Tire tire = new Tire(15);
Bottom bottom = new Bottom(tire);
Frame frame = new Frame(bottom);
Car car = new ioc.Car(frame);
car.init();
}
}
public class Car {
private Frame frame;
public Car(Frame frame) {
this.frame = frame;
}
public void init() {
// 依赖车身
frame.init();
System.out.println("初始化车身");
}
}
public class Frame {
private Bottom bottom;
public Frame(Bottom bottom) {
this.bottom = bottom;
}
public void init() {
// 依赖底盘
bottom.init();
System.out.println("初始化底盘");
}
}
public class Bottom {
private Tire tire;
public Bottom(Tire tire) {
// 传入一个Tire对象给Bottom
this.tire = tire;
}
public void init () {
// 依赖轮胎
tire.init();
System.out.println("初始化底盘");
}
}
public class Tire {
private int size = 20;
public Tire(int size) {
this.size = size;
}
public void init() {
System.out.println("初始化轮胎 " + "【size:" + size + "】");
}
}
这样一来,对轮胎的任何定制化需求都只会在轮胎这个类中修改,上层所有轮均不会受到任何影响
public class CreateCar {
public static void main(String[] args) {
// 造轮胎
Tire tire = new Tire(15, "blue");
Bottom bottom = new Bottom(tire);
Frame frame = new Frame(bottom);
Car car = new ioc.Car(frame);
car.init();
}
}
public class Car {
private Frame frame;
public Car(Frame frame) {
this.frame = frame;
}
public void init() {
// 依赖车身
frame.init();
System.out.println("初始化车身");
}
}
public class Frame {
private Bottom bottom;
public Frame(Bottom bottom) {
this.bottom = bottom;
}
public void init() {
// 依赖底盘
bottom.init();
System.out.println("初始化底盘");
}
}
public class Bottom {
private Tire tire;
public Bottom(Tire tire) {
// 传入一个Tire对象给Bottom
this.tire = tire;
}
public void init () {
// 依赖轮胎
tire.init();
System.out.println("初始化底盘");
}
}
public class Tire {
private int size = 20;
private String color= "red";
public Tire(int size, String color) {
this.size = size;
this.color = color;
}
public void init() {
System.out.println("初始化轮胎 " + "【size:" + size + ";color:" + color+ "】");
}
}
对比这两种实现方式
- 传统:类的创建顺序是反的,
Car
控制并创建了Frame
,Frame
控制并创建了Bottom
,Bottom
控制并创建了Tire
- IoC:将控制权进行翻转,不再是上级对象创建并控制下级对象,而是下级对象注入到上级对象中,下级对象的生命周期又自己掌握
(3)理解Spring IoC
Spring是包含了多个工具方法的IoC容器:
- 容器:具备两个基本功能
- 将对象存入容器
- 从容器中取出对象
- IoC:控制了对象的生命周期(创建、销毁)
你只需要学会如何将对象存入Spring,然后从Spring中获取对象即可。现在你不需要自己new对象了,全由Spring负责
(4)DI
依赖注入(DI):是指IoC容器在运行期间,动态地将某种依赖关系注入到对象之中。因此,DI和IoC描述的是同一件事情,只是角度不同——通过引入IoC容器,利用依赖关系注入的方式,实现对象解耦
评论区