【Spring篇】初识 Spring IoC 与 DI

目录

一.  Spring 是什么 ?

二. 何为 IoC ? 

三. 如何理解 Spring IoC ?

四. IoC 与 DI

五 . 总结


一.  Spring 是什么 ?

    我们通常所说的 Spring 指的是 Spring Framework(Spring 框架),它是⼀个开源框架,有着活跃⽽ 庞⼤的社区,这就是它之所以能⻓久不衰的原因。Spring ⽀持⼴泛的应⽤场景,它可以让 Java 企业级 的应⽤程序开发起来更简单。

  • 以下是 Spring 框架的一些核心特点:
  1. 轻量级:Spring 框架采用了松耦合的设计原则,仅依赖于少量的第三方库,因此它是一个轻量级的框架。开发人员可以根据需要选择使用 Spring 的特定功能,而无需引入整个框架。
  2. 控制反转(IoC):Spring 框架通过控制反转(IoC)容器管理应用程序中的对象及其依赖关系。通过 IoC 容器,开发人员可以将对象的创建、组装和生命周期管理交给 Spring 框架处理,从而实现了松耦合和可测试性。
  3. 面向切面编程(AOP):Spring 框架支持面向切面编程,可以通过 AOP 在应用程序中实现横切关注点的模块化。例如,日志记录、事务管理和安全性等横切关注点可以通过 AOP 进行集中处理,而不会侵入业务逻辑的代码。
  4. 声明式事务管理:Spring 框架提供了声明式事务管理的支持。通过使用注解或 XML 配置,开发人员可以将事务管理逻辑与业务逻辑分离,并且可以轻松地在方法或类级别上应用事务。
  5. 框架整合:Spring 框架可以与许多其他开源框架和技术无缝集成,如 Hibernate、MyBatis、JPA、Struts 和 JSF 等。这使得开发人员可以使用 Spring 框架来整合和协调不同的技术,构建全面的企业应用程序。
  6. 测试支持:Spring 框架提供了广泛的测试支持,包括单元测试和集成测试。它提供了一个专门的测试上下文,可以轻松地编写和执行单元测试,以验证应用程序的行为和功能

如果要使用一句话来概括 Spring , 那就是 Spring是包含了众多工具方法的 IoC 容器 

何为 IoC ? ,  IoC 的全称叫做 Inversion of Control , 即为控制反转 ,也就是说 Spring 是一个控制反转的容器 , 那么怎样理解上述的内容呢 ?

二. 何为 IoC ? 

准确来说 , IoC 指的并不是一种具体的技术, 而是一个实现对象解耦的思想 

耦合 : 当两个或者两个以上的对象存在依赖,一方修改之后就会影响另外一方,就说明这两个对象之间存在这耦合关系 , 而解耦, 就是为了解除这两个对象之间的依赖关系。

那么 IoC 是如何实现对象的解耦呢 ? 

下面通过一个具体的示例来进行讲解 :
       在传统的开发思想中 , 当我们要构建一辆车时 , 而车又依赖于车身, 车身又依赖于底盘,底盘又依赖于轮胎,他们之间的依赖关系如下图所示 :

 当我们使用代码进行实现时 ,所有类之间的调用链如下所示:

// Car类
public class Car {// car 进行初始化时 , 需要调用 frameworkpublic void init(){System.out.println("do car");Framework framework = new Framework();framework.init();}public static void main(String[] args){Car car = new Car();car.init();}
}
// Framework类
public class Framework {// framework 进行初始化时, 调用了Bottompublic void init(){System.out.println("do framework");Bottom bottom = new Bottom();bottom.init();}}
// Bottom 类
public class Bottom{// Bottom 进行初始化时,调用了 Tirepublic void init(){System.out.println("do bottom");Tire tire = new Tire();tire.init();}
}
// Tire 类
public class Tire {private int size = 10;public void init(){System.out.println("size -> "+size);}
}

在上述的代码当中,如果轮胎的尺寸 size 发生了改变,相对应的 底盘,车身,再到整车都要发生一定的变化,也就是当我们在自身类创建下级类时,当下级类发生改变操作,自己也要跟着修改,代码的耦合程度较高,不利于后续的更新和添加元素,所以如何实现程序的解耦呢?

那么如何解决传统开发中的缺陷呢 ?

答案是我们在创建类时,不在每个类中创建下级类,而是改为传递的方式(也就是注入的方式),因为我们不需要在当前类中创建下级类了,所以下级类中即使发生变化,当前类也无需修改任何代码,这样就完成了程序的解耦。

下面我们将参数传递的方式进行修改:

  • 通过将对象进行传递而并非 new 对象的方式来进行解决:
# car类
public class Car {private Framework framework;// 将 framework 注入 carpublic Car(Framework framework) {this.framework = framework;}public void init() {System.out.println("do car...");framework.init();}
}
# framework 类
public class Framework {private Bottom bottom;// bottom 注入 frameworkpublic Framework(Bottom bottom){this.bottom = bottom;}public void init(){System.out.println("do framework");bottom.init();}
}
# bottom类
public class Bottom {private Tire tire;// tire 注入 bottompublic Bottom(Tire tire) {this.tire = tire;}public void init() {System.out.println("do bottom...");tire.init();}
}
# trie 类
package newCar;public class Tire {private int size = 17;private String color = "红色";public Tire(int size, String color) {this.size = size;}public void init() {System.out.println("size -> " + size + " | color -> " + color);}
}
# 测试类
public class Test {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.init();}
}

代码经过上述的调整之后,无论底层的类如何进行改变,整个调用链都不会发生变化,这样就完成了代码之间的解耦。

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

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

再举一个开发中比较简单的例子 :
当我们在开发过程中, A 对象要使用 B对象的 某个方法, 我们通常的实现方法如下 :

class A{public void init(){// new一个B类对象,调用 init()方法B b = new B();b.init();}
}
class B{public B(){}public void init(){System.out.println("hello world!");}
}

此时,A 和 B对象是相互进行耦合的, 当修改了B中构造方法的参数时,A对象也要随之发生改变。

class B {public B(String name){System.out.println("姓名 :"+name);}public void init(){System.out.println("Hello word!");}
}

 那么实际业务中,如何解决上述的问题呢?

与上一个例子类似, 也是通过将对象进行传递(注入)的方式 , 代码如下 :

class A {// 先定义一个需要依赖的 B 对象private B b;// 通过构造方法实现赋值(初始化)public A(B b) {this.b = b;}public void init() {// 调用 B 类中的 init 方法b.init();}
}
class B {public B(String name) {System.out.println("姓名:" + name);}public void init() {System.out.println("Hello World!");}
}

这样修改之后,无论B的构造方法怎么修改,而调用他的A类不需要做任何修改 ,这样就实现了对象的解耦,那么对象的解耦 和 IoC 又有什么关系呢?

通过上边的两个例子,究其原因还是控制权反转的问题 ,A对象对于B对象的管理权交出,交给其他程序来管理,此时A对象对于B对象的管理权发生了反转和改变,这就是 IoC 

三. 如何理解 Spring IoC ?

在 Spring 中, 将 对象交给了 IoC 容器来进行管理 , 不需要关注怎么去创建对象,而是关注创建对象之后的操作, 把对象的创建,初始化,销毁交给了 Spring IoC 容器来管理 。

既然 Spring 是一个IoC容器 ,那么他就具有两个最基础的功能 :

  • 将对象存入到容器
  • 从容器中取出对象

也就是说, 对象的创建和销毁都交给了Spring来管理了,它本身又具备了存储对象和获取对象的能力 。

Spring IoC 的优点有哪些 ?

  • 实现对象解耦
  • 使用更加方便(不需要手动去new创建,和关注对象背后的依赖问题,只关注使用权)
  • 更加高效(从容器中取出对象,不需要重新new)

四. IoC 与 DI

DI 是 Dependency Injection 的缩写,翻译成中文是“依赖注入”的意思。依赖注入不是一种设计实现,而是一种具体的技术,它是在 IoC 容器运行期间,动态地将某个依赖对象注入到当前对象的技术就叫做 DI(依赖注入)

在上述的两个例子当中,对象的传递通过构造方法被动的获取对象,在Spring 中 DI 的实现一般通过注解来主动的获取对象, IoC 是一种设计思想,而 DI 是一种具体的实现技术,比如想吃顿好的是一种思想,但是吃火锅还是串串是一种具体的实现。

Spring中DI有三种 常用的注入方式,后边会详细介绍,下面简单介绍演示一下属性注入:

@Service
public class FrameWork{@Autowiredprivate Bottom bottom;//通过属性注入
}

五 . 总结

     IoC 和 DI 都是 Spring 框架中的重要概念,它们都是用来实现对象解耦的,其中 IoC(控制反转)是一种设计思想,而 DI(依赖注入)是一种具体的实现手段,Spring IoC 中最基础的功能就是对对象的存取。


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

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

相关文章

探秘Spring中Bean的注解宝典:解读存取Bean的相关注解及用法

目录 存储Bean对象Controller(控制器存储)Service(服务存储)Repository(仓库存储)Component(组件存储)Configuration(配置存储)Bean重命名Bean 获取Bean对象属性注入构造方法注入Setter注入Resource(注入关键字) 存储Bean对象 将对象存储在 Spring 中,有两种注解类…

【Linux】信号保存信号处理

前言:对信号产生的思考 上一篇博客所说的信号产生,最终都要有OS来进行执行,为什么?OS是进程的管理者!信号的处理是否是立即处理的?在合适的时候 -》那什么是合适的时候?信号如图不是被立即处理…

Windows安装RabbitMQ

Windows安装RabbitMQ 前言配置erlang环境下载配置环境变量验证 安装RabbitMQ验证 参考 前言 本文并不涉及到RabbitMQ的底层原理,或者别的一些特性说明,仅仅只是安装。 配置erlang环境 因为RabbitMQ是使用该语言开发的。 下载 下载地址: …

《qt quick核心编程》笔记一

1.基础HelloWorld代码 import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Controls 2.15Window {width: 400height: 300visible: truetitle: qsTr("Hello 1World")Rectangle {width: parent.widthheight: parent.heightcolor: "gray"Text {…

【数据挖掘】bytewax 与 ydata工具可实时了解您的数据

一、说明 在这篇博文中,我们将介绍如何将开源流式处理解决方案 bytewax 与 ydata 分析相结合并加以利用,以提高流式处理流的质量。 STream 处理支持在传输中和存储之前对数据进行实时分析,并且可以是有状态的,也可以是无状态的。 …

【网络编程】网络套接字udp通用服务器和客户端

1.预备知识 认识端口号 端口号(port)是传输层协议的内容: 端口号是一个2字节16位的整数(uint16)端口号用来标识主机上的一个进程IP地址port能够标识网络上的某一台主机和某一个进程一个端口号只能被一个进程占用 认识TCP协议 此处我们先对TCP(Transmission Con…

Spring MVC异步上传、跨服务器上传和文件下载

一、异步上传 之前的上传方案,在上传成功后都会跳转页面。而在实际开发中,很多情况下上传后不进行跳转,而是进行页面的局部刷新,比如:上传头像成功后将头像显示在网页中。这时候就需要使用异步文件上传。 1.1 JSP页面 …

[golang gin框架] 41.Gin商城项目-微服务实战之后台Rbac微服务(用户登录 、Gorm数据库配置单独抽离、 Consul配置单独抽离)

上一节抽离了captcha验证码功能,集成了验证码微服务功能,这一节来看看后台Rbac功能,并抽离其中的用户登录,管理员管理,角色管理,权限管理等功能作为微服务来调用 一.引入 后台操作从登录到后台首页,然后其中的管理员管理,角色管理,权限管理等功能可以抽离出来作为 一个Rbac微服…

Python实战

官方文档 请点击下面工程名称,跳转到代码的仓库页面,将工程 下载下来 Demo Code 里有详细的注释 LearnPythonPython 实现功能点demo

OpenCV for Python 实战(一):获取图片拍摄GPS地址并自动添加水印

Hello 我们在OpenCV每天的基础博客当中已经更新了很多了,那么今天我们就来结合前几天的内容。做一个获取属性然后添加对应属性的水印。那让我们赶快开始吧~ 文章目录 图片EXIFPython 获取EXIFexifread库使用方法转换成文字地址 添加水印cv2.putText() 每日总结 图片…

【001 操作系统】什么是线程、进程?线程进程的区别是什么?

一、什么是线程、进程? 进程:进程是资源分配的基本单位,它是程序执行时的一个实例,在程序运行时创建。 在Linux环境下,每个进程有自己各自独立的 4G 地址空间,大家互不干扰对方,如果两个进程之间…

基于大模型的Text2SQL微调的实战教程

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

Homography单应性矩阵

1. Homography 单应性概念 考虑 同一个平面(比如书皮)的两张图片,红点表示同一个物理坐标点在两张图片上的各自位置。在 CV 术语中,我们称之为对应点。 Homography 就是将一张图像上的点映射到另一张图像上对应点的3x3变换矩阵. 因为 Homography 是一个 …

Python模块requests基本用法

简介 Python 的 requests 模块是一个流行的第三方库,用于发送HTTP请求。它提供了一组简洁且易于使用的API,使得在Python中进行网络通信变得更加简单和灵活。 目录 1. 基本概念 1.1. HTTP 协议 1.2. GET 请求 1.3. POST 请求 1.4. get 和 post 的区别…

java本地socket服务端暴露至公网访问【内网穿透】

前言 📕作者简介:热爱跑步的恒川,致力于C/C、Java、Python等多编程语言,热爱跑步,喜爱音乐的一位博主。 📗本文收录于恒川的日常汇报系列,大家有兴趣的可以看一看 📘相关专栏C语言初…

蓝桥杯专题-真题版含答案-【生命之树】【消除尾一】【密码脱落】【生日蜡烛】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 👉关于作者 专注于Android/Unity和各种游…

【Java项目实战-牛客社区】--idea maven配置

第一 IDEA集成Maven插件,并配置Maven 以下步骤中,重点关注红色方框的配置 第二 IDEA 创建 Maven 项目 步骤一:创建模块,选择Maven,点击Next 步骤二:填写模块名称,坐标信息,点击finis…

【技术面试】Java八股文业余选手-下篇(持续更新)

文章目录 5. RocketMQ 消息中间件、RabbitMQ、ActiveMQ【√】5.1 RocketMQ 6. Kafka 大数据量消息中间件、ElasticSearch、ZooKeeper【√】6.1 Kafka【√】6.2 ElasticSearch 7. 分布式、研发提效、高并发、线程安全【√】7.1 分布式与集群【√】7.2 高并发、线程安全【】7.3 研…

【JavaScript】实现网页中的选项卡

一、简易选项卡 以下是实现一个简单选项卡的代码。代码中有注释。 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0"…

Airbnb 引入 HTTP Streaming,网页性能得到大幅度提升

Airbnb 通过引入HTTP Streaming来提升网站的页面加载性能。他们将测试的每个页面&#xff08;包括主页&#xff09;的首次内容绘制&#xff08;First Contentful Paint&#xff0c;FCP&#xff09;时间降低了大约 100 毫秒。他们还最小化了后端慢查询对加载时间的影响。 Airbn…