四、Spring初识IoC和DI
一、初识IoC和DI
1.1Spring是什么?
我们知道了Spring是⼀个开源框架,他让我们的开发更加简单.他⽀持⼴泛的应⽤场 景,有着活跃⽽庞⼤的社区,这也是Spring能够⻓久不衰的原因. 但是这个概念相对来说,还是⽐较抽象. 我们⽤⼀句更具体的话来概括Spring,那就是:Spring是包含了众多⼯具⽅法的IoC容器。
1.1.1 容器
容器是⽤来容纳某种物品的(基本)装置。⸺来⾃:百度百科 ⽣活中的⽔杯,垃圾桶,冰箱等等这些都是容器.
在比如:
List/Map->数据存储容器
Tomcat->Web容器
1.1.2 IoC是什么
在类上⾯添加 @RestController 和 @Controller 注解,就是把这个对象交给Spring管理,Spring框架启动时就会加载该类.把对象交 给Spring管理,就是IoC思想
IoC: Inversion of Control (控制反转),也就是说Spring是⼀个"控制反转"的容器
控制反转是什么?-----> 当需要某个对象时,传统开发模式中需要⾃⼰通过new创建对象,现在不需要再进⾏创建, 把创建对象的任务交给容器, 程序中只需要依赖注⼊(DependencyInjection,DI)就可以了. 这个容器称为:IoC容器. Spring是⼀个IoC容器,所以有时Spring也称为Spring容器.
举个生活中的例子:
想象你每天早上都需要一杯咖啡。通常情况下,你自己去厨房找咖啡机和咖啡豆来做咖啡。但在控制反转的情况下,你的家人已经知道你喜欢喝咖啡,并且在你起床前就把泡好的咖啡放在桌上等你。这里,你不再需要自己去找资源(咖啡机和咖啡豆),而是这些资源被“注入”给了你。这就像是依赖注入,外部环境(你的家人)负责准备并提供你需要的东西这种方式让早晨的流程变得更简单、直接,也更灵活,因为你不需要关心咖啡的准备工作了。这就是控制反转的基本思想:将对象的创建和管理从对象自身转移到外部环境。
1.2 IoC的介绍
1.2.1 传统的程序开发
需求:造一辆车
先设计轮⼦(Tire),然后根据轮⼦的⼤⼩设计底盘(Bottom),接着根据底盘设计⻋⾝(Framework),最 后根据⻋⾝设计好整个汽⻋(Car)。这⾥就出现了⼀个"依赖"关系:汽⻋依赖⻋⾝,⻋⾝依赖底盘,底 盘依赖轮⼦.
代码实现:
import org.w3c.dom.ls.LSOutput;
//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.
public class Main {
public static void main(String[] args) {
Car car = new Car();
}
}
//汽车类
class Car {
private Tramework tramework;
public Car() {
tramework = new Tramework();
System.out.println("Car init...");
}
}
//车身类
class Tramework {
private Bottom bottom;
public Tramework() {
bottom = new Bottom();
System.out.println("Tramework init...");
}
}
//地盘类
class Bottom {
private Tire tire;
public Bottom() {
tire = new Tire();
System.out.println("Bottom init...");
}
}
//轮胎类
class Tire {
private int size;
public Tire() {
this.size = 17;
System.out.println("Tire size : " + this.size);
}
}
当我们要去添加轮胎类的Tire构造方法的形参编译时会出现一层一层的关联报错!
通过上述案例会发现这样的设计 代码可维护型很低,程序的耦合度⾮常⾼(修改⼀处代码,影响其他处的代码修改).
1.2.2 解决方案
尝试换⼀种思路,我们先设计汽⻋的⼤概样⼦,然后根据汽⻋的样⼦来设计⻋⾝,根据⻋⾝来设计 底盘,最后根据底盘来设计轮⼦.这时候,依赖关系就倒置过来了:轮⼦依赖底盘,底盘依赖⻋⾝, ⻋⾝依赖汽⻋。
我们可以尝试不在每个类中⾃⼰创建下级类,如果⾃⼰创建下级类就会出现当下级类发⽣改变操作, ⾃⼰也要跟着修改. 此时,我们只需要将原来由⾃⼰创建的下级类,改为传递的⽅式(也就是注⼊的⽅式),因为我们不 需要在当前类中创建下级类了,所以下级类即使发⽣变化(创建或减少参数),当前类本⾝也⽆需修 改任何代码,这样就完成了程序的解耦.
public class Main {
public static void main(String[] args) {
Tire tire = new Tire(17);
Bottom bottom = new Bottom(tire);
Framework framework = new Framework(bottom);
Car car = new Car(framework);
}
}
//汽车类
class Car {
private Framework tramework;
public Car(Framework framework) {
this.tramework = framework;
System.out.println("Car init...");
}
}
//车身类
class Framework {
private Bottom bottom;
public Framework(Bottom bottom) {
this.bottom = bottom;
System.out.println("Tramework init...");
}
}
//地盘类
class Bottom {
private Tire tire;
public Bottom(Tire tire) {
this.tire = tire;
System.out.println("Bottom init...");
}
}
//轮胎类
class Tire {
private int size;
public Tire(int size) {
this.size = size;
System.out.println("Tire size : " + this.size);
}
}
代码经过以上调整,⽆论底层类如何变化,整个调⽤链是不⽤做任何改变的,这样就完成了代码之间 的解耦,从⽽实现了更加灵活、通⽤的程序设计了。
1.2.3 IoC的优点
在传统的代码中对象创建顺序是:Car->Framework->Bottom->Tire
改进之后解耦的代码的对象创建顺序是:Tire->Bottom->Framework->Car
我们发现了⼀个规律,通⽤程序的实现代码,类的创建顺序是反的,传统代码是Car控制并创建了 Framework,Framework创建并创建了Bottom,依次往下,⽽改进之后的控制权发⽣的反转,不再是使⽤⽅对象创建并控制依赖对象了,⽽是把依赖对象注⼊将当前对象中,依赖对象的控制权不再由当前类控制了. 这样的话,即使依赖类发⽣任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是IoC的 实现思想。
从上⾯也可以看出来,IoC容器具备以下优点:
1、资源不由使⽤资源的双⽅管理,⽽由不使⽤资源的第三⽅管理,这可以带来很多好处。第⼀,资源集 中管理,实现资源的可配置和易管理。
2、降低了使⽤资源双⽅的依赖程度,也就是我们说的耦合度。
3、资源集中管理: IoC容器会帮我们管理⼀些资源(对象等),我们需要使⽤时,只需要从IoC容器中 去取就可以了。
4、我们在创建实例的时候不需要了解其中的细节,降低了使⽤资源双⽅的依赖程度,也就是耦合 度。
1.3 DI 介绍
DI: DependencyInjection(依赖注⼊) 容器在运⾏期间,动态的为应⽤程序提供运⾏时所依赖的资源,称之为依赖注⼊。
依赖注⼊(DI)和控制反转(IoC)是从不同的⻆度的描述的同⼀件事情,依赖注⼊是从应⽤程序的⻆度来描述,就是指通过引⼊IoC容器,利⽤依赖关系注⼊的⽅式,实现对象之间的解耦.
上述代码中,是通过构造函数的⽅式,把依赖对象注⼊到需要使⽤的对象中的
IoC 是⼀种思想,也是"⽬标",⽽思想只是⼀种指导原则,最终还是要有可⾏的落地⽅案,⽽DI就属于 具体的实现。所以也可以说,DI是IoC的⼀种实现.
⽐如说我今天⼼情⽐较好,吃⼀顿好的犒劳犒劳⾃⼰,那么"吃⼀顿好的"是思想和⽬标(是 IoC),但最后我是吃海底捞还是杨国福?这就是具体的实现,就是DI。
二. IoC &DI使用
既然Spring是⼀个IoC(控制反转)容器,作为容器,那么它就具备两个最基础的功能:
• 存
• 取
Spring 容器管理的主要是对象,这些对象,我们称之为"Bean".我们把这些对象交由Spring管理,由 Spring来负责对象的创建和销毁.我们程序只需要告诉Spring,哪些需要存,以及如何从Spring中取出 对象
⽬标:把BookDao,BookService交给Spring管理,完成Controller层,Service层,Dao层的解耦
步骤:
1. Service层及Dao层的实现类,交给Spring管理: 使⽤注解: @Component
2. 在Controller层和Service层注⼊运⾏时依赖的对象:使⽤注解 @Autowired
实现:
1. 把BookDao交给Spring管理,由Spring来管理对象
package com.example.book.dao;
import com.example.book.model.BookInfo;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@Component
public class BookDao {
public List<BookInfo> mockData() {
//对于已知的数据量 建议初始化容量
List<BookInfo> bookInfos = new ArrayList<>(15);
for (int i = 1; i <= 15; i++) {
BookInfo bookInfo = new BookInfo();
bookInfo.setId(1);
bookInfo.setBookName("图书" + i);
bookInfo.setAuthor("作者" + i);
bookInfo.setCount(new Random().nextInt(200));
bookInfo.setPrice(new BigDecimal(new Random().nextInt(100)));
bookInfo.setPublish("出版社" + i);
bookInfo.setStatus(i % 5 == 0 ? 0 : 1);
bookInfos.add(bookInfo);
}
return bookInfos;
}
}
2.把BookService交给Spring管理,由Spring来管理对象
package com.example.book.service;
import com.example.book.dao.BookDao;
import com.example.book.model.BookInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class BookService {
@Autowired
private BookDao bookDao;
public List<BookInfo> getBookList() {
//1、获取图书数据
//2、对图书的数据进行处理
//3、返回数据
//mock 表示虚拟假数据
List<BookInfo> bookInfos =bookDao.mockData();
for (BookInfo bookInfo : bookInfos) {
if (bookInfo.getStatus() == 1) {
bookInfo.setStatusCN("可借阅");
} else {
bookInfo.setStatusCN("不可借阅");
}
}
return bookInfos;
}
}
3.删除创建BookDao的代码,从Spring中获取对象
package com.example.book.service;
import com.example.book.dao.BookDao;
import com.example.book.model.BookInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class BookService {
@Autowired
private BookDao bookDao;
public List<BookInfo> getBookList() {
//1、获取图书数据
//2、对图书的数据进行处理
//3、返回数据
//mock 表示虚拟假数据
List<BookInfo> bookInfos =bookDao.mockData();
for (BookInfo bookInfo : bookInfos) {
if (bookInfo.getStatus() == 1) {
bookInfo.setStatusCN("可借阅");
} else {
bookInfo.setStatusCN("不可借阅");
}
}
return bookInfos;
}
}
4. 删除创建BookService的代码,从Spring中获取对象
package com.example.book.controller;
import com.example.book.model.BookInfo;
import com.example.book.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/book")
public class BookController {
@Autowired
BookService bookService ;
@RequestMapping("/getBookList")
public List<BookInfo> getBookList() {
return bookService.getBookList();
}
}
原文地址:https://blog.csdn.net/m0_63272315/article/details/145263956
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!