【SpringBoot】从零开始全面解析Spring Ioc&DI (一)_springboot di
本篇博客给大家带来的是SpringBoot的知识点, 本篇介绍Spring IoC 和 DI 相关知识.
🐎文章专栏: JavaEE进阶
🚀若有问题 评论区见
❤ 欢迎大家点赞 评论 收藏 分享
如果你不知道分享给谁,那就分享给薯条.
你们的支持是我不断创作的动力 .
王子,公主请阅🚀
- 要开心
-
- 要快乐
-
- 顺便进步
- 1. loC & DI 入门
-
- 1.1 Spring 是什么?
-
- 1.1.1 什么是容器?
- 1.1.2 什么是 IoC?
- 1.2 IoC 具体介绍
-
- 1.2.1 传统程序开发
- 1.2.2 问题分析
- 1.2.3 解决方案
- 1.2.4 IoC 优势
- 1.3 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)。这里就出现了一个\"依赖\"关系:汽车依赖车身,车身依赖底盘,底盘依赖轮子.
最终程序实现代码如下:
1 public class NewCarExample {2 public static void main(String[] args) {3 Car car = new Car();4 car.run();5 }67 /**8 * 汽⻋对象9 */10 public class Car {11 private Framework framework;1213 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 }2122 /**23 * ⻋⾝类24 */25 public class Framework {26 private Bottom bottom;2728 public Framework() {29 bottom = new Bottom();30 System.out.println(\"Framework init...\");31 }32 }3334 /**35 * 底盘类36 */37 public class Bottom {38 private Tire tire;3940 public Bottom() {41 this.tire = new Tire();42 System.out.println(\"Bottom init...\");43 }44 }4546 /**47 * 轮胎类48 */49 public class Tire {50 // 尺⼨51 private int size;5253 public Tire(){54 this.size = 17;55 System.out.println(\"轮胎尺⼨:\" + size);56 }57 }58 }
1.2.2 问题分析
这样的设计看起来没问题,但是可维护性却很低.
如果需求有了变更: 随着对的车的需求量越来越大, 个性化需求也会越来越多,我们需要加工多种尺寸的轮胎。
public class Tire { private int size; public Tire(int size) { System.out.println(\"tire size:\"+this.size); }}
修改之后, 其他调用程序也会报错, 我们需要继续修改:
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 解决方案
如果自己创建下级类就会出现当下级类发生改变,自己也要跟着修改. 因此我们可以尝试不在每个类中创建下级类。
只需要将原来由自己创建的下级类,改为传递的方式(也就是注入的方式),因为我们不需要在当前类中创建下级类了,所以下级类即使发生变化(创建或减少参数),当前类本身也无需修改任何代码,这样就完成了程序的解耦.
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层的解耦。
1. Service层及Dao层的实现类,交给Spring管理: 使用注解: @Component
2. 在Controller层 和Service层 注入运行时依赖的对象: 使用注解 @Autowired
把BookDao 交给Spring管理, 由Spring来管理对象
@Componentpublic 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来管理对象
@Servicepublic 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中获取对象
@Componentpublic 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中获取对象
@RequestMapping(\"/book\")@RestControllerpublic class BookController {// @RequestMapping(\"/getBookList\")// public List getBookList() {// List 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(); }}
本篇博客到这里就结束啦, 感谢观看 ❤❤❤
🐎期待与你的下一次相遇😊😊😊