大白话理解IoC和DI

news2024/11/17 13:39:58

引言

Spring是Java领域最受欢迎的开发框架之一,其核心功能之一就是Spring容器,也就是IoC容器。这篇文章,我们就来聊聊Spring的两大核心功能,控制反转(IOC)和依赖注入(DI)。

文章思路是这样:

  1. 传统开发存在哪些问题
  2. 为了解决这些问题引入IoC 和DI
  3. 总结

传统开发存在的问题

我最早看到IoCDI这两个名词的时候,我脑子里是懵的,理解不了。既然陌生的东西理解不了,我们就看看它为什么出现?它的出现是为了解决什么问题。

我们先假设有三个类,分别为类A、B和C, 其中,main 函数调用了类A, 类A 依赖了类B和类C,类B依赖类C,如果用传统模式开发,大概是下图中的情况,那么传统的这种开发模式存在什么问题呢?看下图,不难发现对于类C,我们在类A 和类B 中都进行了实例化,也就是new了一个C对象 那么:
第一个问题:代码重复,且浪费内存资源。
第二个问题:耦合性太高了,类C是以硬编码的方式创建出来的,如果类C 发生了重大变化,都会直接影响类A和B,
第三个问题:难以测试。在测试过程中,很难将被测试对象与其依赖的对象解耦,从而无法独立地测试被测试对象的逻辑。
第N个问题:其他的就不多说了
在这里插入图片描述

我们有没有什么方式能解决上面这些问题呢? 有,就是IoC和DI。

接下来我们就分析一下IoCDI是怎样解决这些问题的:

什么是IOC?

IoC( Inversion of Control ) 注意哦, 它是一个技术思想,不是一个技术实现。它描述的是 Java开发领域对象的创建,管理问题,我们看了上面的图就知道在传统开发中,存在依赖时,往往都会new一个依赖的对象,那么在IoC 思想下,就不用去new 对象了。而是由IoC容器去帮我们实例化对象并且管理它。

为什么叫控制反转呢?

1.控制了什么?
控制了对象创建、管理的权力

2.反转了什么?
将控制权交给了外部(IoC容器)

如下图:对于对象的创建和管理都交给了IoC容器,当需要使用的时候,不需要去new了,直接去IoC容器中拿。

在这里插入图片描述

什么是DI

DI:Dependancy Injection (依赖注入)

其实DI和IoC是对同一件事情的不同描述,IoC是一种设计原则,是一种思想,而DI是IoC的一种具体实现,前面我们提到,对象统一交给IoC创建并管理,在依赖的地方不需要去new, 这儿就可以理解依赖注入了:

再看看上面的图,类A 依赖类B和C, 注意看图中的伪代码,类A依赖类B和C,那么只需要在类A中声明要依赖的对象,那么通过构造函数注入或者属性注入或者方法注入的方式,将依赖的对象注入到对象中。

IoC是如何解决难以测试问题的呢?

假设我们有一个简单的应用程序,其中有一个服务类 UserService,它依赖于一个数据访问对象 UserDAO 来获取用户信息。我们想要测试 UserService 中的 getUserById 方法,以确保它能够正确地返回指定用户的信息。

首先,我们来看一下没有使用依赖注入的情况:

public class UserService {
    private UserDAO userDAO;

    public UserService() {
        this.userDAO = new UserDAO(); // 在构造函数中直接创建依赖对象
    }

    public User getUserById(int userId) {
        return userDAO.getUserById(userId);
    }
}

public class UserDAOTest {
    @Test
    public void testGetUserById() {
        UserService userService = new UserService(); // 创建被测试对象
        User user = userService.getUserById(1); // 调用方法
        // 断言用户信息是否正确
        assertEquals("husu", user.getName());
        assertEquals("ricardoyhu@163.com", user.getEmail());
    }
}

在上面的代码中,UserService 在构造函数中直接创建了 UserDAO 对象,这样在测试的时候就无法替换掉实际的 UserDAO 对象,导致测试无法独立进行,也无法模拟 UserDAO 的行为。

现在,让我们使用依赖注入来改进代码:

public class UserService {
    @Autowired
    private UserDAO userDAO;

    public User getUserById(int userId) {
        return userDAO.getUserById(userId);
    }
}

public class UserDAOTest {
    @Test
    public void testGetUserById() {
        // 创建模拟的UserDAO对象
        UserDAO mockUserDAO = Mockito.mock(UserDAO.class);
        // 设置模拟对象的行为
        when(mockUserDAO.getUserById(1)).thenReturn(new User(1, "husu", "ricardoyhu@163.com"));
        
        UserService userService = new UserService(mockUserDAO); // 通过构造函数注入模拟对象
        User user = userService.getUserById(1); // 调用方法
        // 断言用户信息是否正确
        assertEquals("husu", user.getName());
        assertEquals("ricardoyhu@163.com", user.getEmail());
    }
}

在上面的代码中,我们@Autowired将 UserDAO 对象注入到了 UserService 中,这样在测试时就可以使用模拟的 UserDAO 对象来替代实际的 UserDAO 对象。我们使用了 Mockito 框架来创建模拟对象,并设置了模拟对象的行为,以模拟 UserDAO 的返回结果。这样一来,我们就可以独立地测试 UserService 中的 getUserById 方法,而不用担心 UserDAO 的实际行为或状态,从而使得测试更加容易进行。

IoC是如何解决代码重复、性能提升的呢?

如何解决代码重复,其实上面已经说到了,就是又IoC容器创建、管理对象,不用到处new了,
说到性能提升就不得不提到IoC容器的生命周期。

IoC容器的生命周期如以下三个阶段

  1. 初始化阶段 : IoC容器在启动时会进行初始化,包括加载配置文件、解析注解、扫描类路径等操作,在这个阶段,IoC容器会创建并管理所有的Bean定义,并根据配置文件或者注解来实例化和装配Bean。
  2. 使用阶段:IoC容器初始化完成后,应用程序可以通过IoC容器来获取所需的Bean对象,并且利用这些对象来完成各种业务逻辑,这个阶段,IoC容器负责管理对象的生命周期,包括对象的创建、依赖注入、初始化等操作。
  3. 销毁阶段:当应用程序关闭时,IoC容器会进行销毁操作,释放资源并销毁所有的Bean对象,在这个阶段,如果Bean类中定义了特定的销毁方法,IOC容器会调用这些方法。如果没有定义销毁方法,IOC容器就不会执行任何额外的销毁操作,而是简单地释放Bean对象所占用的资源,如数据库连接、文件句柄之类的,这个阶段的执行顺序与初始化阶段相关,即先销毁依赖关系较少的Bean,再销毁依赖关系较多的Bean,以保证销毁的顺序正确。

一个Bean 在容器启动时被创建,就会一直存在于容器中,直到应用程序关闭时被销毁,这种管理方式保证了对象的单例性和全局可访问性,也因此提高了系统的性能和效率。

意思就是不会重复创建,不会浪费资源。少了多余的创建和销毁的性能开销,自然就提高系统性能啦。

总结

通过深入理解IOC与DI的核心概念和实践应用,我们可以更好地掌握Spring框架的原理和功能。

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

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

相关文章

C++ 模拟实现 priority_queue(优先队列)

目录 一,优先队列简介 二,priority_queue 的内部实现原理 三,模拟实现 priority_queue 1,模板参数与数据结构 2,构造 3,辅助功能(堆的有序化,建立堆) 4&#xff0…

【数据结构】链表专题2

前言 本篇博客继续探讨有关链表的专题,这片博客的题,提前打个预防针,有点意思哦,哈哈哈,话不多说,进入正文 💓 个人主页:小张同学zkf ⏩ 文章专栏:数据结构 若有问题 评论…

STM32定时器门控模式+单脉冲模式配置

1、实现功能及使用场景: 利用一个主定时器多个从定时器,主定时器控制从定时器的脉冲发送时机和发送个数。 适合用在多轴同步控制的自动化或机器人设备中,同时可以防止系统程序跑飞时运动轴没有停止,提高系统安全。 2、门控模式…

【华为】路由综合实验(基础)

【华为】路由综合实验 实验需求拓扑配置AR1AR2AR3AR4AR5PC1PC2 查看通信OSPF邻居OSPF路由表 BGPBGP邻居BGP 路由表 配置文档 实验需求 ① 自行规划IP地址 ② 在区域1里面 启用OSPF ③ 在区域1和区域2 启用BGP,使AR4和AR3成为eBGP,AR4和AR5成为iBGP对等体…

服务器数据恢复—服务器重装系统导致XFS分区丢失的数据恢复案例

服务器数据恢复环境: 一台服务器MD1200磁盘柜,通过raid卡将15块磁盘组建成一组raid5磁盘阵列。raid5阵列分配了2个lun,操作系统层面对lun进行分区:1个分区采用LVM扩容方式加入到了root_lv中,其余分区格式化为XFS文件系…

Java发送请求-http+https的

第一步:建议ssl连接对象,信任所有证书 第二步:代码同时支持httphttps 引入源码类 是一个注册器 引入这个类,和它的方法create 注册器,所以对http和https都进行注册,参数为id和item,其中http的…

在UI界面中播放视频_unity基础开发教程

在UI界面中播放视频_unity基础开发教程 前言操作步骤结语 前言 之前我写过一篇在场景中播放视频的文章,但是在开发中有时候也会在UI的界面中播放视频,这期我们做一下在UI的界面中播放视频。 操作步骤 首先在场景中创建一个Raw Image,UI->…

Visual 下载 NuGet包速度变慢

Visual 下载 NuGet包速度变慢 最近遇到一个问题,即我在使用 Visual Studio 下载 Nuget 包的时候会发现变得特别慢,那么该如何解决该问题呢 Visual Studio → 工具 → NuGet 包管理项 → 程序包管理设置 → 程序包源 从上面我们可以看到我使用的包源地址…

Codeforces Round 942 (Div. 2) ----- A ----- F --- 题解

前情提要:因为数学水平原因,没法给出e的证明,因为我也是举例归类得出的结论,但是按理来说应该可以利用生成数函数证明 f题也是因为数学原因加上水平有限,我的理解可能有偏差。 目录 A. Contest Proposal&#xff1a…

【无线通信开发应用】nRF905数据手册深度解读

希望通过两个stm32、两个nRF905无线通信模块、串口来实现两机通信。具体功能为: 板子A、B分别包含一个stm32单片机和一个nRF905无线模块,欲实现板子A、B之间的通信。 其中,PC端串口助手可向板子A的stm32发送字符‘A’控制板子B上的LED亮灯&am…

算法系列--多源BFS问题

💕"对相爱的人来说,对方的心意,才是最好的房子。"💕 作者:Lvzi 文章主要内容:算法系列–多源BFS问题 大家好,今天为大家带来的是算法系列--多源BFS问题 前言: 之前我们已经学习过单源的最短路问…

质谱原理与仪器3-笔记

质谱原理与仪器3-笔记 一、质量分析器类型1、聚焦磁场分析器:A、单聚焦磁场分析器B、双聚焦磁场分析器 2、四极杆质量分析器3、飞行时间质谱仪(Time of Flight MS, TOF-MS)4、离子阱质量分析器 二、质谱仪的主要性能指标1、质量范围(mass range)2、分辨率(resolutio…

面试经典150题——Z 字形变换

面试经典150题 day22 题目来源我的题解方法一 使用StringBuilder数组模拟矩阵方法二 找规律直接构造 题目来源 力扣每日一题;题序:6 我的题解 方法一 使用StringBuilder数组模拟矩阵 如果numRows是1,则直接返回s。 否则,创建nu…

python实现的基于单向循环链表插入排序

相比于定义一个循环双向链表来实现插入排序来说,下面的实现采用一个单向循环链表来实现,并且不需要定义一个单向循环链表类,而是把一个list(数组/顺序表)当成单向循环链表来用,list的元素是一个包含两个元素…

26.统一网关Gateway

网关的功能 1.身份认证,权限的校验。 2.服务的路由,负载均衡。用户请求被分配到哪一个微服务。一个微服务可以有多个实例,所以使用负载均衡。 3.请求限流。 springcloud网关实现有两种:gateway, zuul zuul是基于servlet实现的…

Enhancing Diffusion——利用三维透视几何约束增强扩散模型

概述 透视在艺术中被广泛研究,但现代高质量图像生成方法却缺乏透视精度。新的生成模型引入了几何约束,通过训练过程提高透视精度。这样可以生成更逼真的图像,并提高相关深度估计模型的性能。 最近的图像生成技术使研究人员能够创造性地进行…

TCP/IP和HTTP协议

TCP/IP OSI 七层模型在提出时的出发点是基于标准化的考虑,而没有考虑到具体的市场需求,使得该模型结构复杂,部分功能冗余,因而完全实现 OSI 参考模型的系统不多。而 TCP/IP 参考模型直接面向市场需求,实现起来也比较…

App一键直达,Xinstall助力提升用户体验

在这个移动互联网时代,App已经成为了我们日常生活中不可或缺的一部分。然而,每当我们在浏览器或社交平台上看到一个有趣的App推荐,点击下载后却往往要经历一系列繁琐的跳转和确认过程,这无疑大大降低了用户体验。那么,…

工业三废数据集(工业烟粉尘排放量、工业二氧化硫排放量、工业废水排放量)2006-2021年

01、数据介绍 工业三废是指工业生产过程中排出的废气、废水和废渣 工业二氧化硫排放量指企业在燃料燃烧和生产工艺过程中排入大气的二氧化硫数量。 工业烟粉尘排放量是指企业在生产工艺过程中排放的烟尘和粉尘等颗粒物重量。 工业废水排放量是指企业在生产过程中产生的废水…

GPG的使用

这里写自定义目录标题 安装加密程序生成加密密钥怎么备份自己的密钥就可以使用公钥加密邮件信息了 安装加密程序 下载gpg4win: https://www.gpg4win.org/index.html 免费的,如果使用的是苹果电脑,使用https://gpgtools.org/。 如果是linux&a…