
本篇博客给大家带来的是SpringBoot的知识点, 本篇介绍Spring IoC 和 DI 相关知识.
🐎文章专栏: JavaEE进阶
🚀若有问题 评论区见
❤ 欢迎大家点赞 评论 收藏 分享
如果你不知道分享给谁,那就分享给薯条.
你们的支持是我不断创作的动力 .
王子,公主请阅🚀
- 要开心
- [1. loC & DI 入门](#1. loC & DI 入门)
-
- [1.1 Spring 是什么?](#1.1 Spring 是什么?)
-
- [1.1.1 什么是容器?](#1.1.1 什么是容器?)
- [1.1.2 什么是 IoC?](#1.1.2 什么是 IoC?)
- [1.2 IoC 具体介绍](#1.2 IoC 具体介绍)
-
- [1.2.1 传统程序开发](#1.2.1 传统程序开发)
- [1.2.2 问题分析](#1.2.2 问题分析)
- [1.2.3 解决方案](#1.2.3 解决方案)
- [1.2.4 IoC 优势](#1.2.4 IoC 优势)
- [1.3 DI 介绍](#1.3 DI 介绍)
- [2. loC & DI 使用](#2. loC & DI 使用)
-
-
要开心
要快乐
顺便进步
1. loC & DI 入门
1.1 Spring 是什么?
通过前面的学习, 我们知道了Spring是一个开源框架, 他让我们的开发更加简单. 他支持广泛的应用场景, 有着活跃而庞大的社区, 这也是Spring能够长久不衰的原因.
但是这个概念相对来说, 还是比较抽象.
我们用一句更具体的话来概括Spring, 那就是: Spring 是包含了众多工具方法的 IoC 容器 。
那问题来了,什么是 IoC 容器?接下来我们一起来看 .
1.1.1 什么是容器?
容器是用来容纳某种物品的(基本)装置。⸺来自:百度百科
生活中的水杯, 垃圾桶, 冰箱等等这些都是容器.
之前接触的容器有哪些?
List/Map -> 数据存储容器
Tomcat -> Web 容器
1.1.2 什么是 IoC?
这个问题也是常见的面试题。
IoC 是Spring的核心思想. 其实我们在上篇文章就已经使用过 IoC思想了.
在类上面添加 @RestController 和
@Controller 注解, 就是把这个对象交给Spring管理, Spring 框架启动时就会加载该类. 把对象交给Spring管理, 就是IoC思想。
IoC: Inversion of Control (控制反转), 也就是说 Spring 是一个"控制反转"的容器.
控制反转就是 控制权反转. 获得依赖对象的过程被反转了。
也就是说, 当需要某个对象时, 传统开发模式中需要自己通过 new 创建对象, 现在不需要再进行创建, 把创建对象的任务交给容器, 程序中只需要依赖注入 (Dependency Injection,DI)就可以了.
这个容器称为:IoC容器. Spring是一个IoC容器, 所以有时Spring 也称为Spring 容器.
1.2 IoC 具体介绍
通过案例来了解以下什么是 IoC.
需求: 造一辆车.
1.2.1 传统程序开发
传统实现思路是这样的:
先设计轮子(Tire),然后根据轮子的大小设计底盘(Bottom),接着根据底盘设计车身(Framework),最后根据车身设计好整个汽车(Car)。这里就出现了一个"依赖"关系:汽车依赖车身,车身依赖底盘,底盘依赖轮子.

最终程序实现代码如下:
java
1 public class NewCarExample {
2 public static void main(String[] args) {
3 Car car = new Car();
4 car.run();
5 }
6
7 /**
8 * 汽⻋对象
9 */
10 public class Car {
11 private Framework framework;
12
13 public Car() {
14 framework = new Framework();
15 System.out.println("Car init....");
16 }
17 public void run(){
18 System.out.println("Car run...");
19 }
20 }
21
22 /**
23 * ⻋⾝类
24 */
25 public class Framework {
26 private Bottom bottom;
27
28 public Framework() {
29 bottom = new Bottom();
30 System.out.println("Framework init...");
31 }
32 }
33
34 /**
35 * 底盘类
36 */
37 public class Bottom {
38 private Tire tire;
39
40 public Bottom() {
41 this.tire = new Tire();
42 System.out.println("Bottom init...");
43 }
44 }
45
46 /**
47 * 轮胎类
48 */
49 public class Tire {
50 // 尺⼨
51 private int size;
52
53 public Tire(){
54 this.size = 17;
55 System.out.println("轮胎尺⼨:" + size);
56 }
57 }
58 }
1.2.2 问题分析
这样的设计看起来没问题,但是可维护性却很低.
如果需求有了变更: 随着对的车的需求量越来越大, 个性化需求也会越来越多,我们需要加工多种尺寸的轮胎。
java
public class Tire {
private int size;
public Tire(int size) {
System.out.println("tire size:"+this.size);
}
}
修改之后, 其他调用程序也会报错, 我们需要继续修改:
java
public class Bottom {
private Tire tire;
public Bottom(int size) {
tire = new Tire(size);
System.out.println("tire init...");
}
}
public class Framework {
private Bottom bottom;
public Framework(int size) {
bottom = new Bottom(size);
System.out.println("bottom init...");
}
}
public class Car {
private Framework framework;
public Car(int size) {
framework = new Framework(size);
this.framework = framework;
System.out.println("framework init...");
}
public void run() {
System.out.println("car run...");
}
}
从以上代码可以看出,以上程序的问题是:当最底层代码改动之后,整个调用链上的所有代码都需要
修改. 程序的耦合度非常高.
1.2.3 解决方案
如果自己创建下级类就会出现当下级类发生改变,自己也要跟着修改. 因此我们可以尝试不在每个类中创建下级类。
只需要将原来由自己创建的下级类,改为传递的方式(也就是注入的方式),因为我们不需要在当前类中创建下级类了,所以下级类即使发生变化(创建或减少参数),当前类本身也无需修改任何代码,这样就完成了程序的解耦.
java
public class Main {
public static void main(String[] args) {
// Car car = new Car();
// car.run();
Tire tire = new Tire(15);
Bottom bottom = new Bottom(tire);
Framework framework = new Framework(bottom);
Car car = new Car(framework);
car.run();
}
}
public class Car {
private Framework framework;
public Car(Framework framework) {
this.framework = framework;
System.out.println("framework init...");
}
public void run() {
System.out.println("car run...");
}
}
public class Framework {
private Bottom bottom;
public Framework(Bottom bottom) {
this.bottom = bottom;
System.out.println("bottom init...");
}
}
public class Bottom {
private Tire tire;
public Bottom(Tire tire) {
this.tire = tire;
System.out.println("tire init...");
}
}
public class Tire {
private int size;
public Tire(int size) {
System.out.println("tire size:"+this.size);
}
}
代码经过以上调整,无论底层类如何变化,整个调用链是不用做任何改变的,这样就完成了代码之间的解耦,从而实现了更加灵活、通用的程序设计。 这就是 IoC思想.
1.2.4 IoC 优势
在传统的代码中对象创建顺序是:Car -> Framework -> Bottom -> Tire
改进之后解耦的代码的对象创建顺序是:Tire -> Bottom -> Framework -> Car

通用程序的实现代码,类的创建顺序是反的,传统代码是 Car 控制并创建了 Framework,Framework 控制并创建了 Bottom,依次往下,而改进之后的控制权发生的反转,不再是使用方对象创建并控制依赖对象了,而是把依赖对象注入将当前对象中,依赖对象的控制权不再由当前类控制了.
这样的话, 即使依赖类发生任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是 IoC 的实现思想。
从上面也可以看出来, IoC容器具备以下优点:
① 资源不由使用资源的双方管理,而由不使用资源的第三方管理,资源集中管理, 实现资源的可配置和易管理。
② 降低了使用资源双方的依赖程度,也就是耦合度。
1.3 DI 介绍
DI: Dependency Injection(依赖注入)
容器在运行期间, 动态的为应用程序提供运行时所依赖的资源,称之为依赖注入。
当程序运行时需要某个资源,此时容器就为其提供这个资源.
从这点来看, 依赖注入(DI)和控制反转(IoC)是从不同的角度的描述的同一件事情,就是指通过引 入 IoC 容器,利用依赖关系注入的方式,实现对象之间的解耦。
上述代码中, 是通过构造函数的方式, 把依赖对象注入到需要使用的对象中的。

IoC 是一种思想,也是"目标", 而思想只是一种指导原则,最终还是要有可行的落地方案,而 DI 就属于具体的实现。所以也可以说, DI 是IoC的一种实现。
2. loC & DI 使用
既然 Spring 是一个 IoC(控制反转)容器,作为容器, 那么它就具备两个最基础的功能:
• 存
• 取
Spring 容器 管理的主要是对象, 这些对象, 我们称为"Bean". 我们把这些对象交由Spring管理, 由Spring来负责对象的创建和销毁. 我们程序只需要告诉Spring, 哪些需要存, 以及如何从Spring中取出对象。
打开上篇文章spring-book项目, 在service目录下创建BookService文件, 把BookDao, BookService 交给Spring管理, 完成Controller层, Service层, Dao层的解耦。
- Service层及Dao层的实现类,交给Spring管理: 使用注解: @Component
- 在Controller层 和Service层 注入运行时依赖的对象: 使用注解 @Autowired
把BookDao 交给Spring管理, 由Spring来管理对象
java
@Component
public class BookDao {
public List<BookInfo> mockData() {
//理论上该方法应该从数据库获取, 此处先 mock数据.
List<BookInfo> bookInfos = new ArrayList<>();
//mock(模拟) 数据
for (int i = 1; i <= 15; i++) {
BookInfo bookInfo = new BookInfo();
bookInfo.setId(i);
bookInfo.setBookName("图书"+i);
bookInfo.setAuthor("作者"+i);
bookInfo.setNum(i*2+1);
bookInfo.setPrice(new BigDecimal(i*3));
bookInfo.setPublishName("出版社"+i);
if(i % 5 == 0) {
bookInfo.setStatus(2);
// bookInfo.setStatusCN("不可借阅");
}else {
bookInfo.setStatus(1);
// bookInfo.setStatusCN("可借阅");
}
bookInfos.add(bookInfo);
}
return bookInfos;
}
}
把BookService 交给Spring管理, 由Spring来管理对象
java
@Service
public class BookService {
public List<BookInfo> getBookList() {
BookDao bookDao = new BookDao();
List<BookInfo> bookInfos = bookDao.mockData();
for(BookInfo bookInfo : bookInfos) {
if(bookInfo.getStatus() == 2) {
bookInfo.setStatusCN("不可借阅");
}else {
bookInfo.setStatusCN("可借阅");
}
}
return bookInfos;
}
}
删除创建BookDao的代码, 从Spring中获取对象
java
@Component
public class BookService {
@Autowired
private BookDao bookDao;
public List<BookInfo> getBookList() {
// BookDao bookDao = new BookDao();
List<BookInfo> bookInfos = bookDao.mockData();
for(BookInfo bookInfo : bookInfos) {
if(bookInfo.getStatus() == 2) {
bookInfo.setStatusCN("不可借阅");
}else {
bookInfo.setStatusCN("可借阅");
}
}
return bookInfos;
}
}
删除创建BookService的代码, 从Spring中获取对象
java
@RequestMapping("/book")
@RestController
public class BookController {
// @RequestMapping("/getBookList")
// public List<BookInfo> getBookList() {
// List<BookInfo> bookInfos = new ArrayList<>();
// //mock(模拟) 数据
// for (int i = 1; i <= 15; i++) {
// BookInfo bookInfo = new BookInfo();
// bookInfo.setId(i);
// bookInfo.setBookName("图书"+i);
// bookInfo.setAuthor("作者"+i);
// bookInfo.setNum(i*2+1);
// bookInfo.setPrice(new BigDecimal(i*3));
// bookInfo.setPublishName("出版社"+i);
// if(i % 5 == 0) {
// bookInfo.setStatus(2);
// bookInfo.setStatusCN("不可借阅");
// }else {
// bookInfo.setStatus(1);
// bookInfo.setStatusCN("可借阅");
// }
// bookInfos.add(bookInfo);
// }
// return bookInfos;
// }
@Autowired
private BookService bookService;
@RequestMapping("/getBookList")
public List<BookInfo> getBookList() {
// BookService bookService = new BookService();
return bookService.getBookList();
}
}
本篇博客到这里就结束啦, 感谢观看 ❤❤❤
🐎期待与你的下一次相遇😊😊😊