【Spring】(一)Spring设计核心思想
文章目录
- 一、初识 Spring
- 1.1 什么是 Spring
- 1.2 什么是 容器
- 1.3 什么是 IoC
- 二、对 IoC 的深入理解
- 2.1 传统程序开发方式存在的问题
- 2.2 控制反转式程序的开发
- 2.3 对比总结
- 三、对 Spring IoC 的理解
- 四、DI 的概念
- 4.1 什么是 DI
- 4.2 DI 与 IoC的关系
一、初识 Spring
1.1 什么是 Spring
Spring 是一个开源的轻量级 Java 框架,旨在简化 Java 应用程序的开发。它提供了一个全面的编程和配置模型,用于构建各种类型的应用,包括企业级应用和独立的 Java 应用。Spring 的设计理念是基于依赖注入(Dependency Injection)和面向切面编程(Aspect-Oriented Programming),使得应用开发更加模块化、灵活和易于维护。
用一句话概括 Spring 就是:Spring 是一个包含了众多工具的 IoC 容器。
1.2 什么是 容器
所谓容器就是能够盛放东西的器皿,就好像水杯一样。而 Spring 就是一个容器,它的功能就是负责存储和管理应用中的各个组件(Bean),然后在使用的时候从 Spring 中取出需要的 Bean 对象。
1.3 什么是 IoC
IoC,即控制反转(Inversion of Control),是 Spring 框架的核心理念之一。它将应用程序的控制权从开发人员的手中反转,由 Spring 容器负责管理对象的生命周期以及依赖关系。在传统的程序设计中,开发人员需要负责手动创建和管理对象,但是在 IoC 容器中,开发人员只需要定义组件(Bean)的配置元数据,由容器负责实例化、装配和管理这些组件。
二、对 IoC 的深入理解
如果初次理解 IoC,可能会觉得很困难,可以通过下面的例子帮助我们理解 IoC 的作用。
假如,现在需要使用程序来模拟一个简单制造汽车的过程,其实现思路如下:
- 如果要造汽车Car,首先需要有车身Framework;
- 如果需要造车身Framework,首先就需要有地盘Bottom;
- 如果需要造地盘Bottom,首先就需要有轮子Tire。

上述过程,不难发现存在一个依赖链的关系,首先通过传统程序的开发方式,来感受一下其存在的问题。
2.1 传统程序开发方式存在的问题
下面是用传统方式编写的代码:
class Tire {private Integer size = 17;public void init(){System.out.println("do tire: size = " + size);}
}class Bottom {private Tire tire;public Bottom(){this.tire = new Tire();}public void init(){tire.init();System.out.println("do bottom");}
}class Framework {private Bottom bottom;public Framework(){bottom = new Bottom();}public void init(){bottom.init();System.out.println("do framework");}
}class Car {private Framework framework;public Car(){framework = new Framework();}public void init(){framework.init();System.out.println("do car");}
}public class Tradition {public static void main(String[] args) {Car car = new Car();car.init();}
}
在上面的传统写法中,可以发现每个类之间的耦合度非常高,并且每个类都需要管理它所依赖的对象,即掌握着其依赖对象的控制权。此时如果用户的需求改变了,使用的轮子Tire不再是固定的尺寸,而是需要由用户自己输入尺寸的大小,此时Tire类的代码需要更改为:
class Tire {private Integer size = 17;public Tire(int size){this.size = size;}public void init(){System.out.println("do tire: size = " + size);}
}
此时发现,不改不要紧,但是一改问题就来了,由于各个类之间的高耦合性,使得后续所依赖前者的代码都需要进行修改。
class Bottom {private Tire tire;public Bottom(int size){this.tire = new Tire(size);}public void init(){tire.init();System.out.println("do bottom");}
}class Framework {private Bottom bottom;public Framework(int size){bottom = new Bottom(size);}public void init(){bottom.init();System.out.println("do framework");}
}class Car {private Framework framework;public Car(int size){framework = new Framework(size);}public void init(){framework.init();System.out.println("do car");}
}
如果要后续要继续增加 Tire 类的属性,例如color,此时就还要需要从头来进行修改。那么如何解决这个缺陷呢?
上次代码出现这个缺陷的根本原因就在于:当前类将自己所依赖的类的控制权掌握在了自己的手中,即在自己类的内部调用的所依赖类的构造方法。因此解决这个问题的方法也非常简单,那就是不在自己的内部代码中创建所依赖的对象,而是通过参数传递的方式获取这个依赖对象,这就是控制权转移的思想,即 IoC。
2.2 控制反转式程序的开发
下面是转移控制权的代码写法,即将当前类所依赖的对象通过参数的方式进行传入:
class Tire {private Integer size = 17;public Tire(int size) {this.size = size;}public void init() {System.out.println("do tire: size = " + size);}
}class Bottom {private Tire tire;public Bottom(Tire tire) {this.tire = tire;}public void init() {tire.init();System.out.println("do bottom");}
}class Framework {private Bottom bottom;public Framework(Bottom bottom) {this.bottom = bottom;}public void init() {bottom.init();System.out.println("do framework");}
}class Car {private Framework framework;public Car(Framework framework) {this.framework = framework;}public void init() {framework.init();System.out.println("do car");}
}public class IoC {public static void main(String[] args) {Tire tire = new Tire(18, "red");Bottom bottom = new Bottom(tire);Framework framework = new Framework(bottom);Car car = new Car(framework);car.init();}
}
此时,如果用户需求又发生了改变,要求轮子 Tire 的颜色也要自己来挑选,此时更改的代码如下:
class Tire {private Integer size = 17;private String color;public Tire(int size, String color) {this.size = size;this.color = color;}public void init() {System.out.println("do tire: size = " + size + ", color = " + color);}
}
此时,只需要修改 Tire 类和创建 Tire 对象的代码,而不需要对其他代码进行修改。可以发现,即使底层类的改变也不会影响到整个调用链的改变,这样就实现了代码的解耦,从而实现了更加灵活、通用的程序设计方式。

2.3 对比总结
以下是传统代码和 IoC 形式代码的调用过程:

通过对比两种代码的实现方式不难发现:
- 两种代码中类的创建顺序是相反的:
- 传统代码的创建顺序是由顶层 Car 类创建到底层 Tire 类,即:
Car -> Framework -> Bottom -> Tire; - 而 IoC 形式代码的创建顺序则是由底层 Tire 类创建到顶层 Car 类,即:
Tire -> Bottom -> Frame -> Car。
- 传统代码的创建顺序是由顶层 Car 类创建到底层 Tire 类,即:
- 传统代码中,当前类掌握着自己所依赖对象的控制权,耦合度非常高,一旦底层代码修改了,整个调用链的代码都会修改。
- IoC 形式的代码中,当前类通过参数传递的方式,将对所依赖对象的控制权进行反转,即不再有自己掌控,此时无论底层代码如何修改,也不会对整个调用链上的代码造成影响。
三、对 Spring IoC 的理解
“Spring 是一个 包含众多工具的 IoC 容器” 这句话的理解非常重要,因为它揭示了 Spring 框架最核心的功能和优势。在这里,我们可以把 Spring IoC 容器比喻成一个大大的容器,用来存放应用程序中的各种对象(Bean)。这个容器不仅负责对象生命周期的管理,还实现了对象之间的依赖注入(DI),从而实现了控制反转。
既然 Spring 是容器,那么它的核心功能就可以分为两个:
1. 将对象存入容器
- 程序员首先需要创建应用程序中的各种对象(Bean),这些对象代表应用程序中的不同组件和功能模块。
- 然后通过配置文件(如XML、注解或者 Java 配置类)告诉 Spring IoC 容器如何创建这些对象,以及它们之间的依赖关系。
- Spring IoC 容器会根据配置信息,在应用程序启动的时候负责实例化这些对象并存放到容器中,从而完成对象的创建和组装过程。
2. 从容器中取出对象
- 一旦对象被存入了 Spring IoC 容器中,它们就可以在应用程序的其他部分被获取和使用。程序员不需要显示地创建对象,而是从 Spring 容器中直接获取已经创建好的对象来使用。
- 通过依赖注入的方式,Spring IoC 容器会在合适的时候将依赖的对象自动注入到需要它们的地方。
总的来说,Spring IoC 容器负责管理对象的创建、组装和依赖关系,开发人员只需关注对象的定义和配置。通过将对象存入容器并从容器中获取对象,Spring 实现了对象的控制反转,使得应用程序的开发更加简洁、灵活和易于维护。这也是 Spring 框架的核心之一,为开发者提供了一个强大且高度可定制的开发平台。
四、DI 的概念
4.1 什么是 DI
依赖注入(Dependency Injection,DI)是一种实现 IoC 的具体技术,它是 IoC 容器的一种表现形式。在 DI 中,对象之间的依赖关系不再有类自己创建和管理,而是有外部容器(如 Spring)来负责注入依赖的对象。简单来说,DI 就是将一个对象的依赖关系交给外部容器来处理,从而实现对象之间的解耦。
在 DI 中,通常由三种注入方式:
- 构造方法注入(Constructor Injection):通过构造函数接收依赖对象,这是最常见的注入方式。
- Setter 方法注入(Setter Injection):通过Setter方法设置依赖对象。
- 属性注入(Field Injection):通过属性的方式注入依赖对象。
DI 使得对象的依赖关系从代码中移出,变得可配置和灵活。通过使用DI,我们可以在应用程序的不同部分之间实现松耦合,提高代码的可测试性、可维护性和可扩展性。
4.2 DI 与 IoC的关系
DI(依赖注入)和 IoC(控制反转)是紧密相关的概念,通常同时被提及,它们之间的关系可以概括为:
- IoC 是一种设计思想,它将应用程序的控制权从代码内部转移到外部容器。通过 IoC,对象的创建和依赖关系的管理被反转,交由容器来负责管理,而不是由代码显示的控制。
- DI 是实现 IoC 的一种具体技术手段,它是 IoC 的一种表现形式。通过 DI,对象之间的依赖关系由外部容器来注入,而不是由对象自己来创建和管理依赖。
因此,DI 是 IoC 的一部分,它是实现 IoC 的重要手段。Spring 框架正是以 IoC 和 DI 为核心,提供了强大的 IoC 容器和依赖注入机制,从而实现了各种功能,如依赖管理、AOP、事务管理等。通过 IoC 和 DI,Spring 框架实现了松耦合、可配置和可扩展的应用程序开发。
相关文章:
【Spring】(一)Spring设计核心思想
文章目录 一、初识 Spring1.1 什么是 Spring1.2 什么是 容器1.3 什么是 IoC 二、对 IoC 的深入理解2.1 传统程序开发方式存在的问题2.2 控制反转式程序的开发2.3 对比总结 三、对 Spring IoC 的理解四、DI 的概念4.1 什么是 DI4.2 DI 与 IoC的关系 一、初识 Spring 1.1 什么是…...
chrome插件开发实例04-智能收藏夹
目录 功能说明 演示 源码下载 源代码 manifest.json popup.html popup.js background.js 功能说明 基于chrome插件...
iOS技术之 手机系统15.0之后 的 UITableView section header多22像素问题
iOS 15 的 UITableView又新增了一个新属性:sectionHeaderTopPadding 会给每一个section header 增加一个默认高度,当我们 使用 UITableViewStylePlain 初始化 UITableView的时候,就会发现,系统给section header增高了22像素。 解…...
Windows下安装Kafka(图文记录详细步骤)
Windows下安装Kafka Kafka简介一、Kafka安装前提安装Kafka之前,需要安装JDK、Zookeeper、Scala。1.1、JDK安装(version:1.8)1.1.1、JDK官网下载1.1.2、JDK网盘下载1.1.3、JDK安装 1.2、Zookeeper安装1.2.1、Zookeeper官网下载1.2.…...
linuxARM裸机学习笔记(3)----主频和时钟配置实验
引言:本文主要学习当前linux该如何去配置时钟频率,这也是重中之重。 系统时钟来源: 32.768KHz 晶振是 I.MX6U 的 RTC 时钟源, 24MHz 晶振是 I.MX6U 内核 和其它外设的时钟源 1. 7路PLL时钟源【都是从24MHZ的晶振PLL而来…...
防勒索病毒
随着勒索软件攻击在2023年的激增,网络安全已成为当今最重要的议题之一。根据区块链分析公司Chainaanalysis的最新报告,勒索软件攻击已成为唯一呈增长趋势的基于加密货币的犯罪行为,勒索金额更是比一年前增加了近1.758亿美元,达到4…...
剑指 Offer 53 - II. 0~n-1 中缺失的数字
力扣 一个长度为n-1的递增排序数组中的所有数字都是唯一的,并且每个数字都在范围0~n-1之内。在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,请找出这个数字。 示例 1: 输入: [0,1,3] 输出: 2 示例 2: 输入: [0,1,2,3,4,5…...
vue2和vue3区别
vue2和vue3的区别有以下8点: 1、双向数据绑定原理不同; 2、是否支持碎片; 3、API类型不同; 4、定义数据变量和方法不同; 5、生命周期钩子函数不同; 6、父子传参不同; 7、指令与插槽不同&#x…...
IMV3.0
经历了两个版本,基础内容在前面,可以使用之前的基础环境: v1: https://blog.csdn.net/wtt234/article/details/132139454 v2: https://blog.csdn.net/wtt234/article/details/132144907 一、代码组织结构 二、代码 2.…...
怎么在树莓派环境上搭建web网站,并发布到外网可访问,今天教给大家
怎么在树莓派上搭建web网站,并发布到外网可访问? 文章目录 怎么在树莓派上搭建web网站,并发布到外网可访问?概述使用 Raspberry Pi Imager 安装 Raspberry Pi OS测试 web 站点安装静态样例站点 将web站点发布到公网安装 Cpolarcpo…...
大文件传输软件| 生命科学中的关键因素
在2023年,生命科学领域以及其先进的科学技术吸引了人们的目光。这些研究背后,很少有人知道的是,其中涉及了大量的研究数据需要实时进行文件传输,以便于研究,合作,分享,分析,临床试验…...
varint编码实现原理
简言 1. varint即 variable int,也就是变长整型,在mysql,levelDB,protobuf中都有使用 2. varint编码的优点是对数值较小的数进行编码后占用字节较少,比如[0-127]只占用1个字节,[128~16383]只占用2个字节。…...
如果新电脑是刚安装的mysql,但是旧电脑迁移过来的文件里面有相关的rails文件,运行rake db:migrate一直报错
$ bundle exec rake db:migrate#运行完命令报错 rake aborted! LoadError: libmysqlclient.so.21: cannot open shared object file: No such file or directory - /home/meiyi/.asdf/installs/ruby/2.6.9/lib/ruby/gems/2.6.0/gems/mysql2-0.5.5/lib/mysql2/mysql2.so /home/m…...
ChatGPT已闯入学术界,Elsevier推出AI工具
2022年11月,OpenAI公司发布了ChatGPT,这是迄今为止人工智能在现实世界中最重要的应用之一。 当前,互联网搜索引擎中出现了越来越多的人工智能(AI)聊天机器人,例如谷歌的Bard和微软的Bing,看起来…...
深度学习论文: RepViT: Revisiting Mobile CNN From ViT Perspective及其PyTorch实现
深度学习论文: RepViT: Revisiting Mobile CNN From ViT Perspective及其PyTorch实现 RepViT: Revisiting Mobile CNN From ViT Perspective PDF: https://arxiv.org/pdf/2307.09283.pdf PyTorch代码: https://github.com/shanglianlm0525/CvPytorch PyTorch代码: https://gith…...
R语言3_安装SeurateData
环境Ubuntu22/20, R4.1 在命令行中键入, apt-get update apt install libcurl4-openssl-dev libssl-dev libxml2-dev libcairo2-dev libgtk-3-dev # libcairo2-dev :: systemfonts # libgtk :: textshaping进入r语言交互环境,键入, instal…...
详解Gillespie算法:使用Python构建分子化学模拟及其在随机多智能体动力学中的应用
第一部分:Gillespie算法简介 Gillespie算法是一种利用蒙特卡洛抽样模拟化学体系随机动力学行为的方法[3]。它是由Joseph L. Doob提出的,用于生成具有已知反应速率的随机方程组的统计上正确的轨迹(可能的解)[5]。在本文中,我们将详细介绍Gillespie算法的原理,并使用Pytho…...
Unity数字可视化学校_昼夜(三)
1、删除不需要的 UI using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI;public class EnvControl : MonoBehaviour {//UIprivate Button btnTime;private Text txtTime; //材质public List<Material> matListnew Li…...
使用罗技鼠标后 弹出当前页面的脚本发生错误AppData/Local/Temp/LogiUI/Pak/js/jquery-1.3.2.min.js解决
使用的台式机,没有蓝牙驱动,在用logi无线鼠标时,把鼠标连接插入台式机后弹出的如上图所示这个提示,无论是点是/否,还是X掉上图提示,电脑右下角的图依然存在。不习惯这丫的存在。 我重启还是有,然…...
Kubernetes(K8s)从入门到精通系列之十四:安装工具
Kubernetes K8s从入门到精通系列之十四:安装工具 一、kubectl二、kind三、minikube四、kubeadm 一、kubectl Kubernetes 命令行工具 kubectl, 让你可以对 Kubernetes 集群运行命令。 你可以使用 kubectl 来部署应用、监测和管理集群资源以及查看日志。 …...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
uniapp 开发ios, xcode 提交app store connect 和 testflight内测
uniapp 中配置 配置manifest 文档:manifest.json 应用配置 | uni-app官网 hbuilderx中本地打包 下载IOS最新SDK 开发环境 | uni小程序SDK hbulderx 版本号:4.66 对应的sdk版本 4.66 两者必须一致 本地打包的资源导入到SDK 导入资源 | uni小程序SDK …...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...
相关类相关的可视化图像总结
目录 一、散点图 二、气泡图 三、相关图 四、热力图 五、二维密度图 六、多模态二维密度图 七、雷达图 八、桑基图 九、总结 一、散点图 特点 通过点的位置展示两个连续变量之间的关系,可直观判断线性相关、非线性相关或无相关关系,点的分布密…...
从零手写Java版本的LSM Tree (一):LSM Tree 概述
🔥 推荐一个高质量的Java LSM Tree开源项目! https://github.com/brianxiadong/java-lsm-tree java-lsm-tree 是一个从零实现的Log-Structured Merge Tree,专为高并发写入场景设计。 核心亮点: ⚡ 极致性能:写入速度超…...
【PX4飞控】mavros gps相关话题分析,经纬度海拔获取方法,卫星数锁定状态获取方法
使用 ROS1-Noetic 和 mavros v1.20.1, 携带经纬度海拔的话题主要有三个: /mavros/global_position/raw/fix/mavros/gpsstatus/gps1/raw/mavros/global_position/global 查看 mavros 源码,来分析他们的发布过程。发现前两个话题都对应了同一…...
react菜单,动态绑定点击事件,菜单分离出去单独的js文件,Ant框架
1、菜单文件treeTop.js // 顶部菜单 import { AppstoreOutlined, SettingOutlined } from ant-design/icons; // 定义菜单项数据 const treeTop [{label: Docker管理,key: 1,icon: <AppstoreOutlined />,url:"/docker/index"},{label: 权限管理,key: 2,icon:…...
基于谷歌ADK的 智能产品推荐系统(2): 模块功能详解
在我的上一篇博客:基于谷歌ADK的 智能产品推荐系统(1): 功能简介-CSDN博客 中我们介绍了个性化购物 Agent 项目,该项目展示了一个强大的框架,旨在模拟和实现在线购物环境中的智能导购。它不仅仅是一个简单的聊天机器人,更是一个集…...
