【SpringBoot】从零开始全面解析Spring Ioc&DI (一)

【SpringBoot】从零开始全面解析Spring Ioc&DI (一)
在这里插入图片描述
本篇博客给大家带来的是SpringBoot的知识点, 本篇介绍Spring IoC 和 DI 相关知识.
🐎文章专栏: JavaEE进阶
🚀若有问题 评论区见
❤ 欢迎大家点赞 评论 收藏 分享
如果你不知道分享给谁,那就分享给薯条.
你们的支持是我不断创作的动力 .

王子,公主请阅🚀

要开心

要快乐

顺便进步

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)。这里就出现了一个"依赖"关系:汽车依赖车身,车身依赖底盘,底盘依赖轮子.

在这里插入图片描述



最终程序实现代码如下:

1publicclassNewCarExample{2publicstaticvoidmain(String[] args){3Car car =newCar();4 car.run();5}67/** 8 * 汽⻋对象 9 */10publicclassCar{11privateFramework framework;1213publicCar(){14 framework =newFramework();15System.out.println("Car init....");16}17publicvoidrun(){18System.out.println("Car run...");19}20}2122/** 23 * ⻋⾝类 24 */25publicclassFramework{26privateBottom bottom;2728publicFramework(){29 bottom =newBottom();30System.out.println("Framework init...");31}32}3334/** 35 * 底盘类 36 */37publicclassBottom{38privateTire tire;3940publicBottom(){41this.tire =newTire();42System.out.println("Bottom init...");43}44}4546/** 47 * 轮胎类 48 */49publicclassTire{50// 尺⼨51privateint size;5253publicTire(){54this.size =17;55System.out.println("轮胎尺⼨:"+ size);56}57}58}

1.2.2 问题分析


这样的设计看起来没问题,但是可维护性却很低.
如果需求有了变更: 随着对的车的需求量越来越大, 个性化需求也会越来越多,我们需要加工多种尺寸的轮胎。

publicclassTire{privateint size;publicTire(int size){System.out.println("tire size:"+this.size);}}


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

publicclassBottom{privateTire tire;publicBottom(int size){ tire =newTire(size);System.out.println("tire init...");}}publicclassFramework{privateBottom bottom;publicFramework(int size){ bottom =newBottom(size);System.out.println("bottom init...");}}publicclassCar{privateFramework framework;publicCar(int size){ framework =newFramework(size);this.framework = framework;System.out.println("framework init...");}publicvoidrun(){System.out.println("car run...");}}


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

1.2.3 解决方案


如果自己创建下级类就会出现当下级类发生改变,自己也要跟着修改. 因此我们可以尝试不在每个类中创建下级类。
只需要将原来由自己创建的下级类,改为传递的方式(也就是注入的方式),因为我们不需要在当前类中创建下级类了,所以下级类即使发生变化(创建或减少参数),当前类本身也无需修改任何代码,这样就完成了程序的解耦.

publicclassMain{publicstaticvoidmain(String[] args){// Car car = new Car();// car.run();Tire tire =newTire(15);Bottom bottom =newBottom(tire);Framework framework =newFramework(bottom);Car car =newCar(framework); car.run();}}publicclassCar{privateFramework framework;publicCar(Framework framework){this.framework = framework;System.out.println("framework init...");}publicvoidrun(){System.out.println("car run...");}}publicclassFramework{privateBottom bottom;publicFramework(Bottom bottom){this.bottom = bottom;System.out.println("bottom init...");}}publicclassBottom{privateTire tire;publicBottom(Tire tire){this.tire = tire;System.out.println("tire init...");}}publicclassTire{privateint size;publicTire(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来管理对象

@ComponentpublicclassBookDao{publicList<BookInfo>mockData(){//理论上该方法应该从数据库获取, 此处先 mock数据.List<BookInfo> bookInfos =newArrayList<>();//mock(模拟) 数据for(int i =1; i <=15; i++){BookInfo bookInfo =newBookInfo(); bookInfo.setId(i); bookInfo.setBookName("图书"+i); bookInfo.setAuthor("作者"+i); bookInfo.setNum(i*2+1); bookInfo.setPrice(newBigDecimal(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来管理对象

@ServicepublicclassBookService{publicList<BookInfo>getBookList(){BookDao bookDao =newBookDao();List<BookInfo> bookInfos = bookDao.mockData();for(BookInfo bookInfo : bookInfos){if(bookInfo.getStatus()==2){ bookInfo.setStatusCN("不可借阅");}else{ bookInfo.setStatusCN("可借阅");}}return bookInfos;}}


删除创建BookDao的代码, 从Spring中获取对象

@ComponentpublicclassBookService{@AutowiredprivateBookDao bookDao;publicList<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")@RestControllerpublicclassBookController{// @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;// }@AutowiredprivateBookService bookService;@RequestMapping("/getBookList")publicList<BookInfo>getBookList(){// BookService bookService = new BookService();return bookService.getBookList();}}







本篇博客到这里就结束啦, 感谢观看 ❤❤❤
🐎期待与你的下一次相遇😊😊😊

Read more

openclaw 对接完飞书群机器人配置踩坑记:消息不回、Gateway 断开问题排查

openclaw 对接完飞书群机器人配置踩坑记:消息不回、Gateway 断开问题排查

前言 用 OpenClaw 配飞书机器人,踩了两个坑:群消息不回、Gateway 总是断开。排查了好一阵子,总算搞定了,记录一下希望能帮到遇到同样问题的朋友。 发现问题 飞书消息不回复 在飞书群里 @ 了机器人,完全没反应。一开始以为是网络不好或者机器人没上线,但状态显示明明是连接着的,这就奇怪了。 Gateway 频繁断开 每次改完配置跑 openclaw gateway restart,或者根本什么都没干,Gateway 说断就断。再想启动就报错,必须跑一遍 openclaw doctor --fix 重新安装才能用。太影响使用了。 查看原因 飞书机器人 ID 搞错了 翻日志看到这么一句: receive events or callbacks through persistent connection only available in

By Ne0inhk
疆鸿智能EtherCAT转DeviceNet,发那科机器人融入倍福的“焊接红娘”

疆鸿智能EtherCAT转DeviceNet,发那科机器人融入倍福的“焊接红娘”

疆鸿智能EtherCAT转DeviceNet,发那科机器人融入倍福的“焊接红娘” 引言 在汽车制造这样高度自动化、节拍紧凑的生产环境中,各类先进的机器人、PLC以及执行机构往往来自不同厂商,采用不同的总线协议。这种异构网络的“沟通”问题,成为了制约产线柔性和稳定性的关键瓶颈。近期,在某汽车制造厂的车门及配件焊接工段优化项目中,我们成功部署了疆鸿智能EtherCAT转DeviceNet协议转换网关(型号:JH-ECT-MDVN),实现了以倍福(Beckhoff)PLC为主站,通过EtherCAT网络,对发那科(FANUC)机器人(DeviceNet从站)进行精准、高效的实时控制。本文将站在一线调试工程师的视角,深入剖析该网关在设备通讯中所扮演的核心角色,并总结其带来的工程价值。  项目背景:当“高速总线”遇上“成熟节点” 该工段原有的控制系统采用倍福TwinCAT PLC作为主控大脑,其优势在于EtherCAT通讯的高速性与同步性,非常适合多轴联动和快速逻辑处理。然而,工段内的多台发那科焊接机器人,其标准配置的通讯接口为DeviceNet。作为一款成熟且稳定的现场总线,Devic

By Ne0inhk
Xilinx FPGA PCIe | XDMA IP 核 / 应用 / 测试 / 实践

Xilinx FPGA PCIe | XDMA IP 核 / 应用 / 测试 / 实践

注:本文为 “Xilinx FPGA 中 PCIe 技术与 XDMA IP 核的应用” 相关文章合辑。 图片清晰度受引文原图所限。 略作重排,未整理去重。 如有内容异常,请看原文。 FPGA(基于 Xilinx)中 PCIe 介绍以及 IP 核 XDMA 的使用 Njustxiaobai 已于 2023-11-22 16:10:41 修改 一、PCIe 总线概述 1. PCIe 总线架构 PCIe 总线架构与以太网的 OSI 模型类似,是一种分层协议架构,分为事务层(Transaction Layer)、数据链路层(Data Link

By Ne0inhk

【OpenClaw】揭秘 Secure DM Pairing:如何为你的 AI 机器人构建安全私信访问机制

【OpenClaw】揭秘 Secure DM Pairing:如何为你的 AI 机器人构建安全私信访问机制 在构建基于 LLM 的聊天机器人(如 Telegram、WhatsApp Bot)时,如何控制谁能与机器人对话是一个核心安全问题。直接开放访问可能导致 Token 滥用,而手动配置白名单又过于繁琐。 OpenClaw 提供了一套优雅的解决方案,称为 “Secure DM Pairing” (安全私信配对)。本文将深入解析这套机制的运作流程、使用指令以及底层的代码实现。 注意本文基于 OpenClaw v2026.1.29 版本源码分析。 1. 什么是 Secure DM Pairing? Secure DM Pairing 是 OpenClaw 网关默认的一种访问控制策略。 当一个未授权的用户首次通过私信(Direct Message)

By Ne0inhk