Spring常见问题一:IOC和DI
IOC和DI
IOC和DI之间到底是什么关系? 什么是依赖关系?依赖关系会带来什么问题?Spring是怎么来支持依赖注入的?
引言
在现代软件开发中,面向对象编程(OOP)已经成为主流编程范式。然而,随着系统复杂性的增加,传统的OOP也暴露出一些不足。为了更好地管理代码的依赖关系和提高代码的可维护性,依赖注入(Dependency Injection,DI)和控制反转(Inversion of Control,IoC)等设计原则应运而生。本文将深入探讨IoC和DI之间的关系、依赖关系的定义及其问题,以及Spring框架如何支持依赖注入。
一、什么是控制反转(IoC)
控制反转(Inversion of Control,IoC)是一种设计原则,它将对象的创建和依赖关系的管理从代码中剥离出来,交由容器或框架处理。简单来说,IoC的核心思想是将控制权从应用程序代码转移到容器中,使应用程序更加灵活和易于维护。
1.1 IoC的实现方式
IoC有多种实现方式,最常见的包括:
- 依赖注入(Dependency Injection,DI):通过构造函数注入、Setter方法注入或接口注入的方式,将依赖对象传递给需要它们的对象。
- 服务定位器(Service Locator):通过一个集中管理的服务提供者,动态地获取依赖对象。
本文主要关注依赖注入这一实现方式。
1.2 IoC的优势
IoC的主要优势包括:
- 解耦合:通过IoC,组件之间的依赖关系被外部容器管理,减少了代码中的耦合。
- 可测试性:由于依赖对象可以被注入,单元测试时可以轻松地替换实际依赖为模拟对象。
- 可维护性:通过配置文件或注解来管理依赖关系,代码的维护和修改变得更加简单。
二、什么是依赖注入(DI)
依赖注入(Dependency Injection,DI)是控制反转的一种实现方式,它通过外部化依赖关系,将对象的创建和管理交给容器来处理。DI使得对象不需要自己创建依赖对象,而是通过注入的方式获得它们。
2.1 DI的类型
依赖注入主要有三种类型:
-
构造函数注入:通过构造函数将依赖对象注入到目标对象中。
public class Service {private Repository repository;public Service(Repository repository) {this.repository = repository;} } -
Setter方法注入:通过Setter方法将依赖对象注入到目标对象中。
public class Service {private Repository repository;public void setRepository(Repository repository) {this.repository = repository;} } -
接口注入:通过接口方法将依赖对象注入到目标对象中(这种方式较少使用)。
public interface Service {void setRepository(Repository repository); }
2.2 DI的优势
DI的主要优势包括:
- 增强模块化:通过DI,各个模块可以独立开发、测试和部署,降低了模块间的耦合。
- 提高代码可读性:依赖关系通过注入方式显式声明,代码的依赖关系更加清晰。
- 便于单元测试:通过注入模拟对象,单元测试变得更加简单和可靠。
三、什么是依赖关系
依赖关系是指一个对象依赖于另一个对象以完成其功能。在软件开发中,依赖关系是不可避免的,但如果处理不当,会导致代码的耦合性增加,难以维护和扩展。
3.1 依赖关系的定义
在面向对象编程中,依赖关系通常表现为一个类使用另一个类的实例。这种关系可以通过以下几种方式实现:
- 通过构造函数:在对象的构造函数中传递依赖对象。
- 通过方法参数:在方法调用时传递依赖对象。
- 通过成员变量:在类的成员变量中直接引用依赖对象。
3.2 依赖关系的分类
依赖关系可以分为强依赖和弱依赖:
- 强依赖:目标对象的存在完全依赖于依赖对象,缺少依赖对象,目标对象无法工作。
- 弱依赖:目标对象的某些功能依赖于依赖对象,但即使缺少依赖对象,目标对象仍能部分工作。
四、依赖关系带来的问题
不正确地处理依赖关系,会导致一系列问题,包括:
4.1 高耦合
高耦合是指系统中的模块或类之间的依赖关系过于紧密,以至于修改一个模块或类会影响到其他模块或类。高耦合会导致以下问题:
- 代码难以维护:一处修改可能会引发连锁反应,需要修改多个地方。
- 代码难以扩展:添加新功能时,需要修改大量现有代码,增加了出错的风险。
- 单元测试困难:由于模块间依赖紧密,难以独立测试单个模块。
4.2 代码重用性低
高耦合会导致代码的重用性低,因为一个模块或类很难在不修改其他部分的情况下单独使用。
4.3 违反开闭原则
开闭原则(Open/Closed Principle)是指软件实体应该对扩展开放,对修改关闭。高耦合的代码往往需要频繁修改,从而违反了开闭原则。
五、Spring如何支持依赖注入
Spring框架是Java企业级开发中最流行的框架之一,它通过IoC容器来支持依赖注入。Spring的IoC容器负责管理对象的生命周期和依赖关系,从而实现低耦合和高可维护性的目标。
5.1 Spring IoC容器
Spring IoC容器是Spring框架的核心组件之一,它负责实例化、配置和组装对象。Spring IoC容器使用Java的反射机制和配置元数据(XML、Java注解或Java配置类)来管理依赖关系。
5.2 Spring中的依赖注入方式
Spring支持多种依赖注入方式,包括:
-
构造函数注入:
@Component public class Service {private final Repository repository;@Autowiredpublic Service(Repository repository) {this.repository = repository;} } -
Setter方法注入:
@Component public class Service {private Repository repository;@Autowiredpublic void setRepository(Repository repository) {this.repository = repository;} } -
字段注入:
@Component public class Service {@Autowiredprivate Repository repository; }
5.3 配置方式
Spring支持多种配置方式来实现依赖注入,包括:
-
基于XML的配置:
<bean id="repository" class="com.example.Repository" /> <bean id="service" class="com.example.Service"><constructor-arg ref="repository" /> </bean> -
基于注解的配置:
@Configuration public class AppConfig {@Beanpublic Repository repository() {return new Repository();}@Beanpublic Service service() {return new Service(repository());} } -
基于Java配置类:
@Configuration @ComponentScan(basePackages = "com.example") public class AppConfig { }
5.4 Spring中的依赖解析
Spring使用依赖解析策略来确定如何满足依赖关系。主要有以下几种策略:
- 按类型自动装配(byType):根据依赖对象的类型自动装配。
- 按名称自动装配(byName):根据依赖对象的名称自动装配。
- 构造函数自动装配(constructor):通过构造函数自动装配依赖对象。
5.5 Spring中的作用域
Spring中的bean可以有不同的作用域,常见的作用域包括:
- 单例(Singleton):每个Spring IoC容器中只有一个bean实例(默认作用域)。
- 原型(Prototype):每次请求都会创建一个新的bean实例。
- 请求(Request):每个HTTP请求都会创建一个bean实例(用于Web应用程序)。
- 会话(Session):每个HTTP会
话都会创建一个bean实例(用于Web应用程序)。
5.6 Spring中的依赖生命周期管理
Spring IoC容器不仅负责依赖注入,还负责管理bean的生命周期。Spring提供了多个生命周期回调方法,包括:
- 初始化回调(init method):在bean实例化后调用。
- 销毁回调(destroy method):在bean销毁前调用。
可以通过以下两种方式定义生命周期回调方法:
-
在XML配置中定义:
<bean id="exampleBean" class="com.example.ExampleBean" init-method="init" destroy-method="destroy" /> -
使用注解:
@Component public class ExampleBean {@PostConstructpublic void init() {// Initialization logic}@PreDestroypublic void destroy() {// Cleanup logic} }
结论
控制反转(IoC)和依赖注入(DI)是现代软件开发中重要的设计原则和模式。它们通过将依赖关系的管理交给外部容器,从而实现了低耦合、高可维护性和高可测试性的目标。Spring框架作为Java企业级开发的主流框架,通过其强大的IoC容器和丰富的配置方式,提供了全面的依赖注入支持,使开发者能够更加高效地构建复杂的应用程序。
理解IoC和DI的概念和原理,能够帮助开发者编写出更加模块化、可维护和易于测试的代码。在实际开发中,合理应用IoC和DI,可以显著提升代码质量和开发效率。
相关文章:
Spring常见问题一:IOC和DI
IOC和DI IOC和DI之间到底是什么关系? 什么是依赖关系?依赖关系会带来什么问题?Spring是怎么来支持依赖注入的? 引言 在现代软件开发中,面向对象编程(OOP)已经成为主流编程范式。然而࿰…...
LabVIEW红外热波图像缺陷检
开发使用LabVIEW开发的红外热波图像缺陷检测系统。该系统结合红外热像仪、工业相机和高效的数据采集硬件,实现对工件表面缺陷的自动检测和分析。通过LabVIEW的强大功能,系统能够实时采集、处理和显示红外热波图像,有效提高了检测的精度和效率…...
c#与欧姆龙PLC通信——如何更改PLC的IP地址
前言 我们有时候需要改变欧姆龙Plc的ip地址,下图有两种更改方式,一种是已知之前Plc设置的Ip地址,还有一种是之前不知道Pl的Ip地址是多少,下面分别做介绍。 1、已知PLC的IP地址的情况下更改地址 假设已知PLC的Ip地址,比如本文中PLC的IP为192.168.1.2,我首先将电脑的IP地…...
[Spring Boot]定时任务因系统时间修改之后无法执行
问题描述 当Spring Boot启动时,当前时间为2024-01-01 00:00:00。 此时你创建了任务: 每10秒钟触发一次定时任务 Scheduled(cron "0/10 * * * * ? ") public void scheduledTask() { }此时你手动修改了系统时间,修改为2023-12-0…...
【棋盘上的战舰】python刷题记录
目录 小前言 思路: 上代码 lucky ending 小前言 经过漫长的停更周期-----1个月 我决定铁血回归!!! 思路: 两层for循环暴力最快了这种小小范围题,主要是第一行和第一列的边界处理,我分为…...
NoSQL 之Redis集群
Redis集群 主从复制 主从复制(Replication)是 Redis 中一种基本的高可用架构模式,适用于简单的读写分离需求和基本的故障恢复。在主从复制中,一个 Redis 主节点可以拥有多个从节点,主要特点包括: 角色定义&…...
ES13的4个改革性新特性
1、类字段声明 在 ES13 之前,类字段只能在构造函数中声明, ES13 消除了这个限制 // 之前 class Car {constructor() {this.color = blue;this.age = 2...
Flutter EasyRefresh:介绍与使用指南
什么是 Flutter EasyRefresh? Flutter EasyRefresh 是一个强大的下拉刷新和上拉加载组件,用于构建流畅且高效的 Flutter 应用程序。它提供了多种自定义配置和动画效果,使开发者可以轻松实现列表的刷新和加载功能。 主要功能 支持下拉刷新和…...
链表的回文结构(链表的中间节点+反转链表)
链表的回文结构 一.链表的中间节点思路1:暴力求解思路2:快慢指针 二.返回倒数第k个节点思路1:暴力求解思路2:快慢指针 三.反转链表思路1:头插法思路2:反转指针的指向 四.链表的回文结构思路1:利…...
汇编学习基础知识【记录】
前言 又是快乐的学习汇编的一天,时间如白驹过隙,抓紧时间,在学习能力最好的年纪多学习一些知识,朝着美好生活而奋斗!哈哈哈 参考文章: https://blog.csdn.net/Z_H_Z_0/article/details/106574292 知识补…...
【持续集成_06课_Jenkins高级pipeline应用】
一、创建项目选择pipeline的风格 它主要是以脚本(它自己的语言)的方式进行运行,一般由运维去做的事情,作为测试而言。了解即可。 --- 体现形式全部通过脚本去实现:执行之前(拉取代码)执行&…...
taro小程序terser-webpack-plugin插件不生效(vue2版本)
背景 最近在做公司内部的小程序脚手架,为了兼容老项目和旧项目,做了vue2taro,vue3taro两个模板,发现terser-webpack-plugin在vue2和vue3中的使用方式并不相同,同样的配置在vue3webpack5中生效,但是在vue2webpack4中就…...
games103作业2(未完)
PBD方法 首先是每个质点的力的分析,不考虑碰撞和弹簧弹力的情况下,每个质点受重力的影响,所以需要对每个质点进行速度和位置的重力影响更新。 float t 0.0333f; float damping 0.99f; int[] E; float[] L; Vector3[] V; Vector3 gra…...
避免 WebSocket 连接被拒绝
一、检查服务器配置和权限 (一)确认服务器访问权限 确保您的客户端有访问服务器的合法权限。如果服务器设置了访问控制列表(ACL)或仅允许特定的源(Origin)进行连接,您需要确保客户端的请求来源在允许的范围内。例如,如果服务器只允许来自特定域名的连接,而您的客户端从…...
shell中关于数组的使用
shell中关于数组的使用 在Shell中,数组是一种可以存储多个值的变量。数组的每个值都由一个数字索引来访问。在Shell中,数组的索引从0开始。 数组的常见的使用方法包括 数组的定义数组的打印数组长度数组的遍历数组元素的打印数组元素的添加数组元素的…...
python:绘制一元三次函数的曲线
编写 test_x3_3x.py 如下 # -*- coding: utf-8 -*- """ 绘制函数 y x^33x4 在 -3<x<3 的曲线 """ import numpy as np from matplotlib import pyplot as plt# 用于正常显示中文标题,负号 plt.rcParams[font.sans-serif] […...
SAP PP学习笔记26 - User Status(用户状态)的实例,订单分割中的重要概念 成本收集器,Confirmation(报工)的概述
上面两章讲了生产订单的创建以及生产订单的相关内容。 SAP PP学习笔记24 - 生产订单(制造指图)的创建_sap 工程外注-CSDN博客 SAP PP学习笔记25 - 生产订单的状态管理(System Status(系统状态)/User Status(用户状态)),物料的可用性检查,生…...
ctfshow-web入门-php特性(web104-web108)
目录 1、web104 2、web105 3、web106 4、web107 5、web108 1、web104 需要传入的 v1 和 v2 进行 sha1 加密后相等。 解法1: 这里都没有判断 v1 和 v2 是否相等,我们直接传入同样的内容加密后肯定也一样。 ?v21 post: v11 拿到 flag…...
python之集合相关
1.概况 是无序的数据结构 集合内的个体统称为元素,每个元素不可重复 所有元素被放在大括号里面,元素之间通过逗号分隔 集合对象是一组无序的可哈希的值,集合元素是不可变的数据类型 2.定义集合 使用大括号语法 基本语法: {元素1&a…...
【学习笔记】无人机(UAV)在3GPP系统中的增强支持(十一)-无人机服务可用性用例需求
引言 本文是3GPP TR 22.829 V17.1.0技术报告,专注于无人机(UAV)在3GPP系统中的增强支持。文章提出了多个无人机应用场景,分析了相应的能力要求,并建议了新的服务级别要求和关键性能指标(KPIs)。…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
