初识Spring
目录
1.Spring 基础
2.传统程序开发
3.IoC程序开发(解耦)
4.DI
4.1 IoC 和 DI 有什么区别
1.Spring 基础
Spring 指的是 Spring Framework(Spring 框架),它是⼀个开源框架,有着活跃⽽庞⼤的社区,这就是它之所以能⻓久不衰的原因。Spring ⽀持⼴泛的应⽤场景,它可以让 Java 企业级的应⽤程序开发起来更简单。
一句话概括:Spring 是包含了众多工具方法的 IoC 容器
容器:⽤来容纳某种物品的(基本)装置(例如:List/Map ---> 数据存储容器、Tomcat ----> Web 容器)
IoC:IoC = Inversion of Control 翻译成中⽂是“控制反转”的意思,也就是说 Spring 是⼀个“控制反转”的容器
控制(权)反转:对象的生命周期,不是由程序员(或当前代码片段)来控制,而是由 Spring(Spring 容器/ IoC容器)来控制
IoC最大的优点:可以实现解耦(松耦合)
2.传统程序开发
假如,我们现在构建⼀辆“⻋”的程序,我们的实现思路是这样的:

/*** 传统开发:汽车对象*/
public class Car {private Framework framework;//依赖车声,建立车身//在构造方法中 newpublic Car() {this.framework = new Framework();}public void init() {//依赖车身System.out.println("执行了 init 方法");framework.init();}
}
/*** 车身类*/
public class Framework {private Bottom bottom;public Framework() {this.bottom = new Bottom();}public void init() {//依赖底盘System.out.println("执行了 Framework init 方法");bottom.init();}
}
/*** 底盘类*/
public class Bottom {private Tire tire;public Bottom() {this.tire = new Tire();}public void init() {//依赖轮胎System.out.println("执行了 Bottom init 方法");tire.init();}
}
/*** 轮胎类*/
public class Tire {private int size = 15;public void init() {System.out.println("执行了 Tire init,Size:"+ size);}
}
这个时候我们执行这段代码:
public class Test {public static void main(String[] args) {Car car = new Car();car.init();}
}

上述代码中轮胎的尺寸是固定的,然而随着对的车的需求量越来越⼤,个性化需求也会越来越多,这 时候我们就需要加工多种尺⼨的轮胎,那这个时候就要对上面的程序进行修改:
注意每一类中size的改动
/*** 传统开发:汽车对象*/
public class Car {private Framework framework;public Car(int size) {this.framework = new Framework(size);}public void init() {//依赖车身System.out.println("执行了 init 方法");framework.init();}
}/*** 车身类*/
public class Framework {private Bottom bottom;public Framework(int size) {this.bottom = new Bottom(size);}public void init() {//以来底盘System.out.println("执行了 Framework init 方法");bottom.init();}
}/*** 底盘类*/
public class Bottom {private Tire tire;//Botton 中没有size参数,继续让别人传参数public Bottom(int size) {this.tire = new Tire(size);}public void init() {//依赖轮胎System.out.println("执行了 Bottom init 方法");tire.init();}
}/*** 轮胎类*/
public class Tire {private int size = 15;//传递 size 参数public Tire(int size) {this.size = size;}public void init() {System.out.println("执行了 Tire init,Size:"+ size);}
}public class Test {public static void main(String[] args) {Car car = new Car(20);car.init();}
}

这个时候我们发现,虽然我们可以改变轮胎的尺寸,但是最底层代码改动之后,整个调用链上的所有代码都需要修改——耦合性问题
需求指挥越来越多,改动的也会越来越多,这个时候我们就可以使用 IoC 进行解耦
3.IoC程序开发(解耦)
/*** IoC:汽车对象*/
public class Car {private Framework framework;//初始化(不是用传统开发):让框架传入(不管咋样传入),声明使用Framework//如果是一个IoC框架,运行代码,会拿到当前框架中的Framework 赋值到当前变量中就会有 frameworkpublic Car(Framework framework) {this.framework = framework;}public void init() {System.out.println("Car init");framework.init();}
}public class Framework {private Bottom bottom;public Framework(Bottom bottom) {this.bottom = bottom;}public void init() {System.out.println("Framework init");bottom.init();}
}public class Bottom {private Tire tire;public Bottom(Tire tire) {this.tire = tire;}public void init() {System.out.println("Bottom init");tire.init();}
}public class Tire {private int size = 15;public Tire() {}public void init() {System.out.println("Tire init, Size:" + size);}
}/*** 模拟 IoC 容器*/
public class Test {private Tire tire;private Bottom bottom;private Framework framework;private Car car;public Test() {this.tire = new Tire();this.bottom = new Bottom(this.tire);this.framework = new Framework(this.bottom);this.car = new Car(this.framework);}public static void main(String[] args) {Test test = new Test();test.car.init();}
}

需要改尺寸只需要修改 Tire 类中的尺寸:
public class Tire {private int size = 15;public Tire(int size) {this.size = size;}public void init() {System.out.println("Tire init, Size:" + size);}
}
这个时候只需要改 IoC 容器(Spring 框架 )即可(IoC 与用户没有关系),Spring 框架会自动设置参数
public class Test {private Tire tire;private Bottom bottom;private Framework framework;private Car car;public Test() {this.tire = new Tire(20);this.bottom = new Bottom(this.tire);this.framework = new Framework(this.bottom);this.car = new Car(this.framework);}public static void main(String[] args) {Test test = new Test();test.car.init();}
}

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

对比传统:
通⽤程序的实现代码,类的创建顺序是反的,传统代码是 Car 控制并创建了Framework,Framework 创建并创建了 Bottom,依次往下,⽽改进之后的控制权发⽣的反转,不再是上级对象创建并控制下级对象了,⽽是下级对象把注⼊将当前对象中,下级的控制权不再由上级类控制了,这样即使下级类发⽣任何改变,当前类都是不受影响的,这就是典型的控制反转,也就是 IoC 的实现思想。
既然 Spring 是⼀个 IoC(控制反转)容器,重点还在“容器”⼆字上,那么它就具备两个最基础的功能:
- 将对象存入到容器
- 从容器中取出对象
也就是说学 Spring 最核心的功能,就是学如何将对象存入到 Spring 中,再从 Spring 中获取对象的过程
将对象存放到容器中的好处:将对象存储在 IoC 容器相当于将以后可能⽤的所有共具制作好都放到仓库中,需要的时候直接取就行了,用完再把它放回到仓库。而new 对象的方式相当于,每次需要工具了,才现做,用完就扔掉了也不会保存,下次再⽤的时候还得重新做,这就是 IoC 容器和普通程序开发的区别
4.DI
DI 是 Dependency Injection 的缩写,翻译成中文是“依赖注入”的意思:指的是由 IoC 容器在运行期间,动态的将依赖对象获取到的过程
public class Car {private Framework framework;public Car(Framework framework) {this.framework = framework;}public void init() {System.out.println("Car init");framework.init();}
}
在运行 Car 时,动态的将 Framework 拿到当前类中的过程就叫做 依赖注入 (在运行类的时候,需要有一个依赖类,依赖类就会从容器中动态的查询出来,赋值给变量,就可以直接使用这个方法)
所以,依赖注⼊(DI)和控制反转(IoC)是从不同的⻆度的描述的同⼀件事情,就是指通过引⼊ IoC 容器,利⽤依赖关系注⼊的⽅式,实现对象之间的解耦;
IoC 是“目标”也是⼀种思想,而目标和思想只是⼀种指导原则,最终还是要有可行的落地方案,而 DI 就属于具体的实现。
比如说我今天吃⼀顿美餐,那么“美餐”是目标(是 IoC),但最后我是吃火锅还是烧烤?这就是具体的实现,就是DI
4.1 IoC 和 DI 有什么区别
IoC 和 DI 都是 Spring 框架中的核心概念,它们的区别在于:
- IoC(Inverse of Control,控制反转):它是一种思想,主要解决程序设计中的对象依赖关系管理问题。在 IoC 思想中,对象的创建权反转给第三方容器,由容器进行对象的创建及依赖关系的管理。
- DI(Dependency Injection,依赖注入):它是 IoC 思想的具体实现方式之一,用于实现 IoC。在 Spring 中,依赖注入是指:在对象创建时,由容器自动将依赖对象注入到需要依赖的对象中。
简单来说,它们的关系是:
- IoC 是一种思想、理念,定义了对象创建和依赖关系处理的方式。
- DI 是 IoC 思想的具体实现方式之一,实际提供对象依赖关系的注入功能。
所以 IoC 是更基础和广义的概念,DI 可以说是 IoC 的一种实现手段。大多数情况下,我们提到 IoC 的时候,其实意味着 DI,因为 DI 已经是 IoC 最常见和广泛使用的实现方式了。
例如在 Spring 框架中:
- IoC 体现为 Spring 容器承担了对象创建及依赖关系管理的控制权。
- DI 体现为 Spring 容器通过构造方法注入、Setter 方法注入等方式,将依赖对象注入到需要依赖的对象中。
所以综上,IoC 和 DI 之间的关系可以这样理解:
- IoC 是理论,DI 是实践。
- IoC 是思想,DI 是手段。
- IoC 是整体,DI 是部分。
相关文章:
初识Spring
目录 1.Spring 基础 2.传统程序开发 3.IoC程序开发(解耦) 4.DI 4.1 IoC 和 DI 有什么区别 1.Spring 基础 Spring 指的是 Spring Framework(Spring 框架),它是⼀个开源框架,有着活跃⽽庞⼤的社区&…...
Mybatis 使用参数时$与#的区别
之前我们介绍了mybatis中参数的使用,本篇我们在此基础上介绍Mybatis中使用参数时$与#的区别。 如果您对mybatis中参数的使用不太了解,建议您先进行了解后再阅读本篇,可以参考: Mybatis参数(parameterType)https://blog.csdn.net…...
解锁Spring Boot的强大配置功能:@ConfigurationProperties与@PropertySources详解
解锁Spring Boot的强大配置功能:ConfigurationProperties与PropertySources详解 前言什么是ConfigurationProperties和PropertySourcesConfigurationProperties的使用步骤 1: 创建 Java POJO 类步骤 2: 配置类步骤 3: 配置文件步骤 4: 注入配置属性 PropertySources…...
Java和Vue字符串加密
字符串加密 AES 加密算法 在 Java 中,可以使用不同的加密算法来对字符串进行加密。以下是使用 AES 加密算法的示例代码,演示如何对一个字符串进行加密: import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java…...
Java:java版结巴分词:jieba-analysis
文档 https://github.com/huaban/jieba-analysishttps://mvnrepository.com/artifact/com.huaban/jieba-analysis 依赖 <!-- https://mvnrepository.com/artifact/com.huaban/jieba-analysis --> <dependency><groupId>com.huaban</groupId><art…...
java生成一个符合密码学和安全性的随机秘钥
有时 我们在生成token 或者完成某种加密形式时会需要一个秘钥 但是 有些时候 项目开发并没有规定用什么秘钥 但是 秘钥都是要有一定格式规范的 我们可以通过以下代码生成一个随机秘钥 import java.security.SecureRandom; import java.util.Base64;public class TokenGenerat…...
C++ - 右值引用 和 移动拷贝
右值引用 我们先来了解什么是左值,什么是右值: 左值 和 有值 区分 首先,左值 和 右值 并不是完全意味着 在 "" 左边的就是 左值 ; 在 "" 右边的就是右值。这是不一定的。只能说,在左边的大概率是…...
项目成员积分规则
在当下的项目/团队管理种,如何让成员能清晰的看到,自己的工作、努力在团队种属于那个段位,通过这个形式,并配合其他方式去点燃成员的进步之心。以积分的形式,代替绩效考核,一些零散的想法,欢迎各…...
Linux CentOS7 vim多窗口编辑
我们在用vim编辑文件时,有各种需求。如有时需要在多个文件之间来回操作,一会关闭一个文件,一会再打开另外一个文件,这样来回操作显得太笨拙。有时,vim编辑多行的大文件,来回查看、编辑前面一部分及最后一部…...
git使用,一点点
查看自己有没有安装git git --version 如果没有安装请执行sudo yum install -y git来安装 git 指令 git log 查看日志 git pull 同步远端和本地仓库 这就是冲突的报错: 所以这个时候你要同步一下git pull...
第五章:最新版零基础学习 PYTHON 教程—Python 字符串操作指南(第八节 - 如何在 C/C++、Python 和 Java 中分割字符串?)
通过某些分隔符分割字符串是一项非常常见的任务。例如,我们有一个文件中以逗号分隔的项目列表,并且我们希望数组中包含各个项目。 几乎所有编程语言都提供按某些分隔符分割字符串的函数。 目录 在C中: 在 C++ 中 方法一:使用C++的stringstream API...
【Java】语法特性篇
语法特性篇 Java对象的比较 1. 对象比较的问题 Java中引用类型的变量不能直接按照 > 或者 < 方式进行比较。那为什么可以比较? 因为:对于用户实现自定义类型,都默认继承自Object类,而Object类中提供了equal方法…...
Vim教程
目录 vim 介绍 常用的四种模式 首先先学会如何正确进入和退出vim: normal模式 insert模式: command模式: v-block模式: vim异常退出 vim配置 vim 介绍 Vim是一款高度可定制的文本编辑器,它的前身是Vi…...
selenium查找网页如何处理网站资源一直加载非常卡或者失败的情况
selenium查找网页如何处理网站资源一直加载失败的情况 selenium获取一个网页,某个网页的资源卡了很久还没有加载成功,如何放弃这个卡的数据,继续往下走 有2钟方式。通常可以采用下面的方式一来处理这种情况 方式一、WebDriverWait 这种方式…...
并发工具类库使用的常见问题
一、ThreadLocal在多线程环境中没有清理 由于ThreadLocal是和线程绑定的,如果线程被复用了,也即使用了线程池,那么ThreadLocal中的值是可能被复用的,这个特性如果是开发者没有预料到的,那么会产生很大的问题。例如&am…...
GD32F10X ----RTC
1. RTC的简介 STM32 的实时时钟(RTC)是一个独立的定时器。STM32 的 RTC 模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。 RTC 模块和时钟配置…...
使用UiPath和AA构建的解决方案 1. 机器人过程自动化入门
你好!在这本系列,我们将指导您完成一些真实世界的机器人过程自动化(RPA)项目。感谢您的加入。当你完成本系列时,你将具备使用UiPath和Automation Anywhere在最低指导下进行简单到中等复杂度RPA项目的知识、技术和心态。 RPA是一项令人兴奋的新技术,被视为使用新的先进技…...
rust字面量
字面量就是值。值最终必须编码成二进制存储在某块内存上。 变量与字面量的关系就像杯子和水的关系。 字面量是有类型的。字面量类型有:布尔、数字、文本、字节 一、布尔 类型是bool true false 二、数字 通过后缀表示类型 通过前缀表示进制 通过 “_” 来分割数…...
Unix Network Programming Episode 79
‘gai_strerror’ Function The nonzero error return values from getaddrinfo have the names and meanings shown in Figure 11.7. The function gai_strerror takes one of these values as an argument and returns a pointer to the corresponding error string. #incl…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
2021-03-15 iview一些问题
1.iview 在使用tree组件时,发现没有set类的方法,只有get,那么要改变tree值,只能遍历treeData,递归修改treeData的checked,发现无法更改,原因在于check模式下,子元素的勾选状态跟父节…...
ffmpeg(四):滤镜命令
FFmpeg 的滤镜命令是用于音视频处理中的强大工具,可以完成剪裁、缩放、加水印、调色、合成、旋转、模糊、叠加字幕等复杂的操作。其核心语法格式一般如下: ffmpeg -i input.mp4 -vf "滤镜参数" output.mp4或者带音频滤镜: ffmpeg…...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
