Spring IoC和DI

Spring IoC和DI

目录

IoC

引入

传统实现思路

解决方案

IoC的优势

DI


Spring 是包含了众多⼯具⽅法的 IoC 容器.

IoC

什么是IoC?

像在类上⾯添加 @RestController 和@Controller 注解, 就是把这个对象交给Spring管理, Spring 框架启动时就会加载该类. 把对象交给Spring管理, 就是IoC思想.

IoC:Inversion of Control (控制反转), 也就是说 Spring 是⼀个"控制反转"的容器.

什么是控制反转呢? 也就是控制权反转. 什么的控制权发⽣了反转? 获得依赖对象的过程被反转了也就是说, 当需要某个对象时, 传统开发模式中需要⾃⼰通过 new 创建对象, 现在不需要再进⾏创建, 把创建对象的任务交给容器, 程序中只需要依赖注⼊ (Dependency Injection,DI)就可以了.
这个容器称为:IoC容器. Spring是⼀个IoC容器, 所以有时Spring 也称为Spring 容器.
引入
传统实现思路

我们的实现思路是这样的:
先设计轮⼦(Tire),然后根据轮⼦的⼤⼩设计底盘(Bottom),接着根据底盘设计⻋⾝(Framework),最后根据⻋⾝设计好整个汽⻋(Car)。这⾥就出现了⼀个"依赖"关系:汽⻋依赖⻋⾝,⻋⾝依赖底盘,底盘依赖轮⼦. 

代码实现

public class Main { public static void main(String[] args) { Car car = new Car(21); car.run(); Car car2 = new Car(17); car2.run(); } } //汽车 class Car { private Framework framework; public Car(int size) { framework = new Framework(size); System.out.println("framework init..."); } public void run() { System.out.println("car run..."); } } //车身 class Framework { private Bottom bottom; public Framework(int size) { bottom = new Bottom(size); System.out.println("bottom init...."); } } //底盘 class Bottom { private Tire tire; public Bottom(int size) { tire = new Tire(size); System.out.println("tire init..."); } } //轮胎 class Tire { private int size; public Tire(int size) { System.out.println("tire size:"+size); } }

上面这样的设计看起来没问题,但是可维护性却很低,因为需求可能会越来越多,比如增加轮胎颜色,修改后的代码如下:

我们可以看到,修改后的代码会报错,并且需要我们继续修改

完整代码如下:

public class Main { public static void main(String[] args) { Car car = new Car(21,"aaa"); car.run(); Car car2 = new Car(17,"bbb"); car2.run(); } } //汽车 class Car { private Framework framework; public Car(int size,String color) { framework = new Framework(size,color); System.out.println("framework init..."); } public void run() { System.out.println("car run..."); } } //车身 class Framework { private Bottom bottom; public Framework(int size,String color) { bottom = new Bottom(size,color); System.out.println("bottom init...."); } } //底盘 class Bottom { private Tire tire; public Bottom(int size,String color) { tire = new Tire(size,color); System.out.println("tire init..."); } } //轮胎 class Tire { private int size; private String color; public Tire(int size,String color) { System.out.println("tire size:"+size); } }

从以上代码可以看出,以上程序的问题是:当最底层代码改动之后,整个调⽤链上的所有代码都需要修改.
程序的耦合度⾮常⾼(修改⼀处代码, 影响其他处的代码修改)。

解决方案

我们尝试改变实现方式:轮⼦依赖底盘, 底盘依赖⻋⾝,⻋⾝依赖汽⻋。

基于以上思路,我们把调⽤汽⻋的程序⽰例改造⼀下,把创建⼦类的⽅式,改为注⼊传递的⽅式。

完整代码如下:

class Main { public static void main(String[] args) { Tire tire = new Tire(17, "red"); Bottom bottom = new Bottom(tire); Framework framework = new Framework(bottom); Car car = new Car(framework); car.run(); } } //汽车 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..."); } } //车身 class Framework { private Bottom bottom; public Framework(Bottom bottom) { this.bottom = bottom; System.out.println("bottom init...."); } } //底盘 class Bottom { private Tire tire; public Bottom(Tire tire) { this.tire=tire; System.out.println("tire init..."); } } //轮胎 class Tire { private int size; private String color; public Tire(int size, String color) { System.out.println("tire size:"+size+",color:"+color); } }

代码经过以上调整,⽆论底层类如何变化,整个调⽤链是不⽤做任何改变的,这样就完成了代码之间的解耦,从⽽实现了更加灵活、通⽤的程序设计了。

IoC的优势

在传统的代码中对象创建顺序是:Car -> Framework -> Bottom -> Tire
改进之后解耦的代码的对象创建顺序是:Tire -> Bottom -> Framework -> Car

我们发现了⼀个规律,通⽤程序的实现代码,类的创建顺序是反的,传统代码是 Car 控制并创建了Framework,Framework 创建并创建了 Bottom,依次往下,⽽改进之后的控制权发⽣的反转,不再是使⽤⽅对象创建并控制依赖对象了,⽽是把依赖对象注⼊将当前对象中,依赖对象的控制权不再由当前类控制了.
这样的话, 即使依赖类发⽣任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是 IoC 的实现思想。

到这⾥, 我们⼤概就知道了什么是控制反转了, 那什么是控制反转容器呢, 也就是IoC容器。

这部分代码, 就是IoC容器做的⼯作.
从上⾯也可以看出来, IoC容器具备以下优点:
资源不由使⽤资源的双⽅管理,⽽由不使⽤资源的第三⽅管理,这可以带来很多好处。

第⼀,资源集中管理,实现资源的可配置和易管理。

第⼆,降低了使⽤资源双⽅的依赖程度,也就是我们说的耦合度。

1. 资源集中管理: IoC容器会帮我们管理⼀些资源(对象等), 我们需要使⽤时, 只需要从IoC容器中去取就可以了
2. 我们在创建实例的时候不需要了解其中的细节, 降低了使⽤资源双⽅的依赖程度, 也就是耦合度.

Spring 就是⼀种IoC容器, 帮助我们来做了这些资源管理. 

DI

DI: Dependency Injection(依赖注⼊)
容器在运⾏期间, 动态的为应⽤程序提供运⾏时所依赖的资源,称之为依赖注⼊。

程序运⾏时需要某个资源,此时容器就为其提供这个资源.

从这点来看, 依赖注⼊(DI)和控制反转(IoC)是从不同的⻆度的描述的同⼀件事情,就是指通过引⼊ IoC 容器,利⽤依赖关系注⼊的⽅式,实现对象之间的解耦。

前面代码中, 是通过构造函数的⽅式, 把依赖对象注⼊到需要使⽤的对象中的。

IoC 是⼀种思想,也是"⽬标", ⽽思想只是⼀种指导原则,最终还是要有可⾏的落地⽅案,⽽ DI 就属于具体的实现。所以也可以说, DI 是IoC的⼀种实现.

Read more

2026 AI“龙虾”大战!OpenClaw、MaxClaw、AutoClaw、QClaw、ArkClaw、KimiClaw、LobsterAI等9款产品横评 + 场景推荐,谁值得你“养”?

2026 AI“龙虾”大战!OpenClaw、MaxClaw、AutoClaw、QClaw、ArkClaw、KimiClaw、LobsterAI等9款产品横评 + 场景推荐,谁值得你“养”?

2026 AI“龙虾”大战!OpenClaw、MaxClaw、AutoClaw、QClaw、ArkClaw、KimiClaw、LobsterAI等9款产品横评 + 场景推荐,谁值得你“养”? 🦞 2026年开年,最火的不是新GPT,而是“养龙虾”! 一只来自奥地利的开源AI Agent框架OpenClaw,以26万+ GitHub Stars一举登顶全球TOP1,超越React和Linux!它能真正“动手干活”:操控浏览器、发邮件、写代码、整理Excel、甚至远程微信控制电脑,被大家亲切叫作“小龙虾”。 大厂们闻风而动:MiniMax、月之暗面、智谱、腾讯、火山引擎、网易有道、阿里云等纷纷推出简化版/云托管版,门槛从“极客专属”降到“小白5分钟上手”。 本文横评9款主流产品(OpenClaw原版 + 8大商业/优化版)

By Ne0inhk
玩转Linux CAN/CAN FD—SocketCAN的使用

玩转Linux CAN/CAN FD—SocketCAN的使用

导语: SocketCAN是CAN协议在Linux系统上的一种主流的实现方式,SocketCAN使用套接字API、Linux网络栈技术,将CAN设备驱动程序实现为网络接口,使其有着易用、兼容性好等特点。 更多SocketCAN的详情可以查看以下文档: https://www.kernel.org/doc/html/v4.17/networking/can.html 本文将从驱动(内核、pcan驱动)到使用(can-utils),带你轻松入门socketcan。  一、配置  本节将从驱动、查找设备、设置波特率、设备状态等几个方面进行介绍。 驱动检查: 检查设备是否已经安装CAN驱动模块 lsmod | grep peak_usb 如果有返回结果,说明设备此时有驱动,可以直接使用; 如果没返回结果,就尝试安装驱动。 sudo modprobe peak_usb 安装成功后,再次使用第一条命令检查; 若返回如下命令,则表示内核中没有包含驱动。

By Ne0inhk
Flutter 三方库 sealed_currencies 构建鸿蒙多汇率电商跨域货币适配:引入 ISO 无状态密封实体消除因非标准币种解析诱发的数据链路崩溃-适配鸿蒙 HarmonyOS ohos

Flutter 三方库 sealed_currencies 构建鸿蒙多汇率电商跨域货币适配:引入 ISO 无状态密封实体消除因非标准币种解析诱发的数据链路崩溃-适配鸿蒙 HarmonyOS ohos

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 sealed_currencies 构建鸿蒙多汇率电商跨域货币封装适配:全量引入 ISO 无状态密封实体消除因非标准币种解析诱发的数据链路断崖式崩溃 在开发金融交易、跨境电商或国际差旅类应用时,对货币数据的精准管理是决定业务逻辑稳定性的关键。sealed_currencies 提供了一套基于密封类(Sealed Classes)思想的货币数据集。本文将深度解析该库在 OpenHarmony 上的适配要点与建模实践。 前言 什么是 sealed_currencies?相比于单纯使用字符串(如 “USD”, “CNY”)来表示货币,该库将每种法定货币抽象为一个强类型的对象,包含其完整的 ISO 代码、数字代码、符号以及最小单位(子单位)。在鸿蒙操作系统致力于全球化分发的背景下,利用强类型的货币数据集,可以有效避免因拼写错误或格式不一导致的严重的业务资损。 一、原理解析 1.1 基础概念 每一个

By Ne0inhk
[linux仓库]信号产生[进程信号·贰]

[linux仓库]信号产生[进程信号·贰]

🌟 各位看官好,我是! 🌍 Linux == Linux is not Unix ! 🚀 今天来学习Linux的信号产生,从多种信号产生方式反推理解之前一直未解决的疑惑。 👍 如果觉得这篇文章有帮助,欢迎您一键三连,分享更多人哦! 目录 信号产生 信号产生方式 键盘产生 kill命令产生 函数产生信号 kill系统调用 raise abort  软件条件 验证IO效率问题 理解闹钟 模拟OS行为 硬件异常 理解 /0 理解野指针 如何理解键盘产生信号? 总结 信号产生 对信号的概念进行一定的理解后,就可以从时间维度上讲解信号产生的话题 信号产生方式 键盘产生 * Ctrl+C (SIGINT) 已经验证过,这⾥不再重复 * Ctrl+\(SIGQUIT)可以发送终⽌信号并⽣成core dump⽂件,⽤于事后调试(

By Ne0inhk