Spring IoC DI(1)

IoC & DI入门

Spring

通过前面的学习, 我们知道了Spring是一个开源框架, 它让我们的开发更加简单. 它支持广泛的应用场景, 有着活跃且庞大的社区, 这就是Spring能够长久不衰的原因.

但是这个概念还是比较抽象.

可以用更具体的话描述Spring, 那就是: Spring是包含了众多工具方法的IoC容器.

那问题来力, 什么是容器? 什么是IoC容器? 

什么是容器

容器是用来容纳某种物品的(基本)装置.

我们想想, 之前接触的容器有哪些?

List/Map -> 数据存储容器

Tomcat -> Web容器

什么是IoC

IoC是Spring的核心思想, 也是常见的面试题, 那什么是IoC呢? 

IoC我们已经使用了, 我们在前面讲到, 在类上面添加@RestController 和@Controller注解,就是把这个对象交给Spring管理, Spring框架启动时就会加载该类. 把对象交给Spring管理, 就是IoC思想.

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

什么是控制反转呢?也就是控制权反转. 什么的控制权发生了反转? 获得依赖对象的过程被反转了. 也就是说, 当需要某个对象时, 传统开发模式中只需要自己通过new创建对象, 现在不需要再进行创建, 把创建对象的任务交给容器, 程序中只需要依赖注入就可以了.

这个容器称为: IoC容器. Spring是一个IoC容器, 所以有时Spring也称为Spring容器.

控制反转是一种思想, 在生活中也处处体现.

当人们斗地主时, 如果手里只剩下王炸, 可以不用管了, 整个托管即可.

在自动驾驶中, 驾驶员可以掌握驾驶的控制权, 也可以将这个控制权交给自动化驾驶系统.

IoC介绍

接下来我们通过案例来了解一下什么是IoC.

需求: 造一辆车

传统程序开发

我们的实现思路是这样的:

先设计轮子(Tire), 然后根据轮子的大小设计出底盘(Bottom), 接着根据底盘的设计车身(Framework), 最后根据车身设计好整辆汽车(Car). 这里就出现了一个"依赖"关系: 汽车依赖车身, 车身依赖底盘, 底盘依赖轮子.

 最终实现的代码如下:

public class NewCarExample {public static void main(String[] args) {Car car = new Car();car.run();}/*** 汽车对象*/static class Car {private FrameWork frameWork;public Car() {frameWork = new FrameWork();System.out.println("Car init...");}public void run() {System.out.println("Car run...");}}/*** 车身类*/static class FrameWork {private Bottom bottom;public FrameWork() {this.bottom = new Bottom();System.out.println("Frame init...");}}/*** 底盘类*/static class Bottom {private Tire tire;public Bottom() {this.tire = new Tire();System.out.println("Bottom init...");}}/*** 轮胎类*/static class Tire {//尺寸private int size;public Tire() {this.size = 17;System.out.println("轮胎尺寸: " + size);}}
}

问题分析

这样的设计看起来没问题, 但是可维护性却很低.

接下来需求有了变更: 随着对车的需求量越来越大, 个性化需求也越来越多, 我们需要加工多种尺寸的轮胎.

那这个时候就要对上面的程序进行修改了, 修改后的代码如下:

 

修改之后, 其它调用程序也会报错, 我们需要修改继续修改(即每一个构造方法都要传一个size) 

完整代码如下:

public class NewCarExample {public static void main(String[] args) {Car car = new Car(20);car.run();}/*** 汽车对象*/static class Car {private FrameWork frameWork;public Car(int size) {frameWork = new FrameWork(size);System.out.println("Car init...");}public void run() {System.out.println("Car run...");}}/*** 车身类*/static class FrameWork {private Bottom bottom;public FrameWork(int size) {this.bottom = new Bottom(size);System.out.println("Frame init...");}}/*** 底盘类*/static class Bottom {private Tire tire;public Bottom(int size) {this.tire = new Tire(size);System.out.println("Bottom init...");}}/*** 轮胎类*/static class Tire {//尺寸private int size;public Tire(int size) {this.size = size;System.out.println("轮胎尺寸: " + size);}}
}

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

程序的耦合度非常高(修改一处代码, 影响其它处代码的修改).

问题解决

在上面的程序当中, 我们是根据轮子的尺寸设计底盘, 轮子尺寸一改, 底盘的设计就得修改. 同样因为我们是根据底盘设计的车身, 那么车身也得修改, 同理汽车设计也得修改, 也就是整个设计都会改.

我们尝试换一种思路, 我们先设计汽车的大概样子, 然后根据汽车的样子来设计车身, 根据车身来设计底盘, 最后根据底盘来设计轮子, 这时, 依赖关系就倒置过来了: 轮子依赖底盘, 底盘依赖车身, 车身依赖汽车.

如何来实现呢?

我们可以尝试不在每个类中创建自己的下级类, 如果自己创建下级类就会出现下级类改变操作, 自己也要跟着修改.

此时, 我们只需要将原来由自己创建的下级类, 改为传递的方式(也就是注入的方式), 因为我们不需要在当前类中创建下级类了, 所以下级类即使发生变化(创建或者减少参数), 当前类不用再改变代码了, 这就实现了程序的解耦.

public class NewCarExample1 {public static void main(String[] args) {Tire tire = new Tire(20);Bottom bottom = new Bottom(tire);FrameWork frameWork = new FrameWork(bottom);Car car = new Car(frameWork);car.run();}static class Car {private FrameWork frameWork;public Car(FrameWork frameWork) {this.frameWork = frameWork;System.out.println("Car init...");}public void run() {System.out.println("Car run...");}}static class FrameWork {private Bottom bottom;public FrameWork(Bottom bottom) {this.bottom = bottom;System.out.println("FrameWork init...");}}static class Bottom {private Tire tire;public Bottom(Tire trie) {this.tire = trie;System.out.println("Bottom init...");}}static class Tire {private int size;public Tire(int size) {this.size = size;System.out.println("Tire init...");}}
}

代码通过以上调整, 无论底层类如何变化, 整个调用类是不用做任何改变的, 这样就实现了代码之间的解耦, 从而实现更加灵活, 通用的程序设计了. 

 IoC优势

在传统的代码中对象的创建对象的顺序是: Car -> FrameWork -> Bottom ->  Tire

改进之后解耦的代码的对象的创建顺序是: Tire -> Bottom -> FrameWork -> Car

我们发现一个规律, 通用程序的实现代码, 类的创建顺序是反的, 传统代码是Car控制并创建了FrameWork, 依次向下, 而改进之后的控制权发生了反转,  不再是使用方对象创建并控制依赖对象了, 而是把依赖对象注入到当前对象中, 依赖对象的控制权不再由当前类控制了.

因此即使依赖类发生任何改变, 当前类都是不受影响的, 这就是典型的控制反转, 也就是IoC的实现思想.

学到这里, 我们就大概知道什么是控制反转了, 那什么是控制反转容器呢,也就是IoC容器.

 

这部分代码就是IoC容器所做的工作.

从上面也可以看出, IoC具有以下优点:

资源不再由资源的双方管理, 而由不使用资源的第三方管理, 这可以带来很多好处.

第一: 资源的集中管理, 实现资源的可配置和易管理, 用的时候只需要从IoC容器中取即可.

第二:降低了使用资源双方的依赖程度, 也就是我们说的耦合度.

DI介绍

DI:Dependency Injection(依赖注入).

容器在运行期间, 动态的为应用程序提供运行时所依赖的资源, 称之为依赖注入

程序运行时需要某个资源, 容器就可以提供这个资源.

从这点来看, IoC(控制反转)和DI(依赖注入)是从不同角度描述同一件事情, 就是指通过引入IoC容器, 利用依赖关系注入的方式, 实现对象之间的解耦.

之前的代码中, 就是通过构造函数的方式, 将依赖的对象注入到需使用对象中.

 

DI是IoC的一种实现. 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/770129.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Jakarta项目介绍

概述 在升级Spring Boot到3.0版本以后,或升级Spring到6.0版本以上,会发现应用编译失败或启动失败等问题。 经过排查不难得知,Spring 6或Spring Boot 3(实际上依赖于Spring 6)不再支持javax.开头的一系列依赖包&#…

人工智能的迷惑行为:AI世界的隐秘角落

人工智能迷惑行为大赏 在当今数字化时代,人工智能技术的飞速发展给我们的生活带来了诸多便利和可能性,但同时也伴随着一些令人困惑的现象和行为。本文将深入探讨人工智能的迷惑行为,揭示AI世界中的隐秘角落,让我们一同探寻这个充…

《深入浅出LLM 》(二):大模型基础知识

🎉AI学习星球推荐: GoAI的学习社区 知识星球是一个致力于提供《机器学习 | 深度学习 | CV | NLP | 大模型 | 多模态 | AIGC 》各个最新AI方向综述、论文等成体系的学习资料,配有全面而有深度的专栏内容,包括不限于 前沿论文解读、…

CPU缓存行及伪共享

CPU Cache概述 随着CPU的频率不断提升,而内存的访问速度却没有质的突破,为了弥补访问内存的速度慢,充分发挥CPU的计算资源,提高CPU整体吞吐量,在CPU与内存之间引入了一级Cache。随着热点数据体积越来越大,…

代码随想录算法训练营第三十二天 | 122.买卖股票的最佳时机II ,55. 跳跃游戏 , 45.跳跃游戏II

贪心&#xff1a;只要把每一个上升区间都吃到手&#xff0c;就能一直赚 class Solution { public:int maxProfit(vector<int>& prices) {int res 0;for(int i 1;i< prices.size();i){int diff prices[i] - prices[i-1];if(prices[i] > prices[i-1]){res d…

蓝桥杯练习题总结(二)dfs题、飞机降落、全球变暖

目录 一、飞机降落 二、全球变暖 初始化和输入 确定岛屿 DFS搜索判断岛屿是否会被淹没 计算被淹没的岛屿数量 三、军训排队 一、飞机降落 问题描述&#xff1a; N架飞机准备降落到某个只有一条跑道的机场。其中第 i 架飞机在 时刻到达机场上空&#xff0c;到达时它的剩余…

[Linux]文件缓冲区

文件fd 输出重定向除了用dup2()改变数组下标外&#xff0c;还可以用命令来完成 所有的命令执行&#xff0c;都必须有操作系统将其运行起来变成进程&#xff0c;然后根据>>, <<来判断是输入重定向&#xff0c;还是输出重定向。 缓冲区 之所以有缓冲区&#xff0…

JavaScript 基础、内置对象、BOM 和 DOM 常用英文单词总结

一提到编程、软件、代码。对于英语不是很熟悉的同学望而却步。其实没有想像中的难么难&#xff0c;反复练习加上自己的思考、总结&#xff0c;会形成肌肉记忆。整理一下&#xff0c;初学者每天30遍。 1、JavaScript 基础语法 break&#xff1a;中断循环或 switch 语句的执行。…

安卓转鸿蒙竟如此丝滑

随着鸿蒙的爆火&#xff0c;大家都想知道鸿蒙能不能搞&#xff1f; 相信大家搞开发的&#xff0c;都多多少少的了解过鸿蒙。近几个月鸿蒙的大动作也不少&#xff0c;如&#xff1a;重庆市近20个垂域应用与鸿蒙原生合作、深圳制定鸿蒙《行动计划》、阿里再次与鸿蒙展开合作&…

微信小程序开发技巧:canvas实现电子签名

在微信小程序中实现电子签名功能方式很多,本文采用canvas绘制的方式实现。具体实现步骤如下: 在页面中添加canvas元素 <view class"container"><canvas canvas-id"signCanvas" class"canvas" disable-scrolltrue touchstart"sta…

跨时钟域学习记录(一)

亚稳态 亚稳态是电平介于高低电平之间的一种暂时状态。在同步系统中&#xff0c;当寄存器的信号无法满足建立时间和保持时间时&#xff0c;输出端的信号就可能出现亚稳态。在异步系统中&#xff0c;亚稳态并非一定在建立时间和保持时间无法满足时出现。   受噪声、温度、电压…

【vue3.0】实现导出的PDF文件内容是红头文件格式

效果图: 编写文件里面的主要内容 <main><div id"report-box"><p>线索描述</p><p class"label"><span>线索发现时间:</span> <span>{{ detailInfoVal?.problem.createdDate }}</span></p><…

MyBatis3源码深度解析(二十一)动态SQL实现原理(二)动态SQL解析过程、#{}和${}的区别

文章目录 前言8.5 动态SQL解析过程8.5.1 SQL配置转换为SqlSource对象8.5.2 SqlSource转换为静态SQL语句 8.6 #{}和${}的区别8.7 小结 前言 在【MyBatis3源码深度解析(二十)动态SQL实现原理(一)动态SQL的核心组件】中研究了MyBatis动态SQL相关的组件&#xff0c;如SqlSource用于…

AAC相关知识

一、AAC音频格式种类有哪些 AAC音频格式是一种由MPEG-4标准定义的有损音频压缩格式。AAC包含两种封装格式 ADIF&#xff08;Audio Data Interchange Format音频数据交换格式&#xff09;和ADTS&#xff08;Audio Data transport Stream音频数据传输流&#xff09;。 ADIF 特点…

promethus的安装使用

1、# 软件下载地址 https://prometheus.io/download/ https://grafana.com/grafana/download https://prometheus.io/download/ Prometheus是一套开源的监控&报警&时间序列数据库的组合,起始是由SoundCloud公司开发的。 Prometheus 的优点 1、非常少的外部依赖,安装…

OceanBase4.2.2.1 单机集群在ArmX86安装(自测记录)

OceanBase OceanBase就不必多加介绍了&#xff0c;本次主要是分享对于它的安装使用&#xff0c;先说说背景&#xff0c;首先接触是因为信创国产化的要求&#xff0c;为满足支持国产化&#xff0c;安装了Arm架构下版本4.0.0&#xff0c;满足支持通过。后来项目实际使用&#xff…

由浅到深认识Java语言(20):包装类

该文章Github地址&#xff1a;https://github.com/AntonyCheng/java-notes 在此介绍一下作者开源的SpringBoot项目初始化模板&#xff08;Github仓库地址&#xff1a;https://github.com/AntonyCheng/spring-boot-init-template & CSDN文章地址&#xff1a;https://blog.c…

leetcode刷题日记-外观数组

题目描述 解题思路 初始化字符串 init 为 “1”&#xff0c;作为外观数列的第一项。 通过循环迭代生成外观数列的下一项&#xff0c;循环次数为 n-1&#xff0c;因为已经初始化了第一项。 在每次迭代中&#xff0c;通过两个指针 pos 和 start 来遍历当前项 init&#xff0c;po…

C++中的枚举类型

C中的enum&#xff08;枚举&#xff09;类型是一种用户定义的类型&#xff0c;用于表示一组整数值&#xff0c;每个值都有对应的名称&#xff0c;增强了代码的可读性和可维护性。 1. 基本枚举类型 基本的枚举类型定义了一组命名的整数常量。 enum Color {RED,GREEN,BLUE };C…