深入浅出讲解Spring IOC和DI的区别
Spring IOC和DI的区别
一,介绍
前言
很多人都会把ioc和di说成同一个东西,其实IOC和DI虽然在概念上可以笼统地视为同一事物,但其本质上存在区别。IOC(Inverse of Control,控制反转)从容器的角度描述,而DI(Dependency Injection,依赖注入)则从应用程序的角度描述。换言之,IOC是依赖倒置原则的设计思想,而DI则是该原则的具体实现方式。因此,我们希望能够更加严谨地区分这两个概念,以更好地理解和应用它们。
1.什么是IOC
Spring IOC(控制反转)是一种设计模式,是Spring框架的核心,它通过将对象之间的依赖关系交由容器来管理和注入,实现了组件之间解耦、松耦合的目的。在传统的Java开发中,对象之间的依赖关系通常是通过手动创建和维护对象之间的引用关系来实现的,这样会带来很多问题,例如代码的可读性、可维护性、可测试性等方面都会受到影响。使用IOC后,无需手动创建和维护对象之间的引用关系,因为Spring容器将自动完成这些工作,并且可以根据需要动态地注入不同类型的对象或数据,从而实现灵活性更强、代码质量更高的应用程序开发。
简单理解就是原本我们创建对象的过程是我们手动来管理的,比如User user = new User(); 而使用ioc就是来解决这个问题的,交给容器来管理创建以及管理的过程
IOC容器的初始化有两种方式:饿汉式初始化和懒加载。
饿汉式初始化是指在容器启动时,立即进行对象的创建和初始化。这种方式适合单例对象,可以保证对象在系统启动时便可用,避免因为对象未初始化而导致的空指针异常等问题。
懒加载则是指只有在需要使用对象时,才进行对象的创建和初始化。这种方式适合非单例对象,可以降低系统启动时间和内存消耗。Spring IoC容器默认使用懒加载方式,只有在使用`@Lazy`注解或者在配置文件中进行特别声明后,才会使用饿汉式初始化方式。
下面是两种初始化方式的示例:
1. 饿汉式初始化方式
@Component
public class MySingletonBean {// ...
}@Configuration
public class AppConfig {@Beanpublic MySingletonBean mySingletonBean() {return new MySingletonBean();}
}
在这个示例中,`MySingletonBean`是一个单例对象,通过在配置类中定义`@Bean`方法来进行饿汉式初始化。
2. 懒加载方式
@Component
@Lazy
public class MyLazyBean {// ...
}
在这个示例中,`MyLazyBean`是一个非单例对象,在它上面使用了`@Lazy`注解,表示使用懒加载方式进行初始化。当应用程序需要使用`MyLazyBean`时,才会触发对象的创建和初始化。
2.什么是DI
Spring DI(依赖注入)是Spring框架中的一个核心特性,它是实现控制反转(IOC)的具体方式之一。DI指的是通过外部配置或注解的方式,将一个对象所依赖的其他对象(依赖)自动注入到该对象中,而不需要在代码中显式地创建和管理这些依赖对象。
通过使用DI,我们可以将对象之间的依赖关系从代码中解耦出来,提高代码的可读性、可维护性和可测试性。Spring框架通过提供不同的DI实现方式(如构造方法注入、Setter方法注入、注解注入等),使得开发者可以根据需求选择合适的注入方式。
例如,我们可以使用构造方法注入,在对象创建时通过构造方法接收所需的依赖对象;或者使用Setter方法注入,在对象创建后通过Setter方法设置所需的依赖对象;还可以使用注解注入,在代码中使用注解标记需要注入的依赖对象。这样,我们就能够以一种更灵活、简洁的方式管理对象之间的依赖关系,提升开发效率和代码质量。
3.为什么要使用控制反转,能给我带来哪些好处
知其然而不知其所以然,是指只知道事物的表面现象!只知道用只是之所以然要明白为什么要用才是知其然而知其所以然。用一东西的时候而不是会用就可以了,要明白为什么要用,难道就没有别的替代方法吗,答案肯定是有的,有人会说就是好用才用的,说的没有错,但是这样我认为并没有去思考为什么要用它为不用别的。接下来我来重点讲解
使用Spring的控制反转(IOC)能够带来以下好处:
1. 解耦合:将程序中的依赖关系转到Spring容器进行配置,可以减少程序模块之间的耦合。这样,当一个组件发生改变时,不会影响到系统中其他组件的正常运行。
2. 管理对象的生命周期:Spring容器负责管理对象的生命周期,当对象不再被使用时,容器会自动销毁其实例,这可以避免内存泄漏等问题。
3. 提高代码重用性:通过将业务逻辑从代码中分离出来,可以使得代码更加可重用,降低代码的维护成本。
4. 模块化开发:Spring容器可以组织程序中的所有对象,使得代码具有良好的层次结构和模块化特性,提高代码的可读性和可维护性。
5. 容易测试:通过控制反转,我们可以使用Mock对象来替代真正的对象进行单元测试,从而使得测试变得更加容易,可以提高代码的质量。
总之,使用Spring控制反转可以使得代码的耦合度更低、可重用性更高、可维护性更好,使得开发工作变得更加高效。
二,代码具体实现
在Spring Boot中,IoC的实现方式与传统的Spring框架类似,但会更加简化和自动化。下面是一个使用Spring Boot实现IoC的示例:
1. 创建一个Spring Boot项目,并添加所需的依赖。2. 编写一个接口和相应的实现类:
// 定义一个接口
public interface MessageService {String getMessage();
}// 实现接口
@Service
public class HelloWorldService implements MessageService {@Overridepublic String getMessage() {return "Hello, World!";}
}
3. 在启动类上使用`@SpringBootApplication`注解,它包含了`@ComponentScan`注解,来自动扫描并创建所有需要的Bean。
@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
4. 在其他需要使用该服务的地方,可以通过`@Autowired`注解来自动注入该Bean。
@RestController
public class MyController {@Autowiredprivate MessageService messageService;@GetMapping("/message")public String getMessage() {return messageService.getMessage();}
}
在这个示例中,我们创建了一个名为 `HelloWorldService` 的bean,并使用 `@Service` 注解来标识它是一个服务类。然后,在启动类中使用 `@SpringBootApplication` 注解来开启Spring Boot应用,并自动扫描和创建所有需要的Bean。
在 `MyController` 中,我们使用 `@Autowired` 注解自动注入了 `MessageService` 类型的bean。然后,在 `/message` 接口中调用 `getMessage()` 方法并返回结果。
Spring Boot会自动注入相关的Bean,并管理它们的生命周期,无需手动配置XML文件。同时,Spring Boot也提供了默认的配置,让开发者可以快速开始项目,减少了繁琐的配置过程。
1.详细详解 IOC
在经典的三层架构中,IoC(控制反转)的具体表示通常是在数据访问层(Repository或DAO)和业务逻辑层(Service)之间的交互。具体来说,IoC容器负责管理并注入数据访问层所需的依赖对象,例如数据库连接、事务管理等。
在这种情况下,数据访问层(Repository或DAO)负责与数据库进行交互,而业务逻辑层(Service)则负责处理业务规则和流程。业务逻辑层需要依赖数据访问层提供的持久化功能,但它并不直接依赖具体的实现类,而是通过IoC容器来获取相应的依赖对象。
通过IoC容器的管理,我们可以在业务逻辑层中使用依赖注入(Dependency Injection)来获取和使用数据访问层的对象,从而实现了对象之间的解耦和灵活性。这样,在需要替换或扩展特定功能时,只需调整IoC容器的配置即可,而不需要修改业务逻辑层的代码。
总结起来,IoC的具体表示通常体现在数据访问层和业务逻辑层之间的交互,通过IoC容器的管理和依赖注入来实现对象的解耦和可替换性。这样可以提高代码的可维护性和可测试性,并支持应用程序的灵活性和扩展性。
2.详细详解 DI
DI(依赖注入)是IoC(控制反转)的一种实现方式,它通过将对象的依赖关系交由容器来管理,从而解耦对象之间的依赖关系。而@Autowired注解是Spring框架中实现依赖注入的一种方式。使用@Autowired注解可以将需要依赖的对象自动注入到目标对象中,由Spring容器负责创建和管理这些被注入的Bean对象。
对于@Autowired注解,它确实是由它来实现依赖注入,将依赖对象注入到IOC容器中,并由容器来负责管理Bean对象的生命周期。当我们在需要使用某个依赖对象的地方添加@Autowired注解后,Spring会自动扫描并查找与该依赖类型匹配的Bean对象,并自动将其注入进来。
所以您可以说@Autowired注解可以实现依赖注入,由它将依赖对象注入到IoC容器进行管理,并由容器负责管理Bean对象的生命周期。非常感谢您的理解和提问!
简单来说 而di就好理解了@Autowired注解 由它依赖注入到ioc容器中由容器来管理bean的生命周期
三,DI依赖注入的几种实现方式
@Resource 这里代码我就不过多介绍了
我来给您提供几种常见的Spring DI(依赖注入)实现方式,并附上相应的代码示例。
1. 构造函数注入(Constructor Injection):
public class UserService {private UserRepository userRepository;@Autowiredpublic UserService(UserRepository userRepository) {this.userRepository = userRepository;}// 其他方法...
}
2. 属性注入(Setter Injection):
public class UserService {private UserRepository userRepository;@Autowiredpublic void setUserRepository(UserRepository userRepository) {this.userRepository = userRepository;}// 其他方法...
}
3. 接口注入(Interface Injection):
public interface UserRepositoryAware {void setUserRepository(UserRepository userRepository);
}public class UserService implements UserRepositoryAware {private UserRepository userRepository;@Overridepublic void setUserRepository(UserRepository userRepository) {this.userRepository = userRepository;}// 其他方法...
}
4. 注解注入(Annotation Injection):
public class UserService {@Autowiredprivate UserRepository userRepository;// 其他方法...
}
5. XML配置注入(XML Configuration Injection):
在XML配置文件中定义Bean和依赖项,并通过<property>元素进行注入。示例:
<bean id="userRepository" class="com.example.UserRepositoryImpl" />
<bean id="userService" class="com.example.UserService"><property name="userRepository" ref="userRepository" />
</bean>
上述示例展示了几种常见的Spring DI实现方式。根据您的需求和项目结构,选择适合的方式来实现依赖注入。
四,@Autowired,@Resource
1.介绍
`@Autowired`和`@Resource`都是Java的注解,用于实现依赖注入(DI)功能。它们可以将依赖对象自动注入到需要的地方,简化了手动创建和管理对象之间的依赖关系的过程。
1. `@Autowired`注解:
- `@Autowired`是Spring框架提供的注解,用于自动装配依赖对象。
- 使用`@Autowired`可以直接在字段、构造方法、Setter方法或者任意方法上标注,Spring将根据类型进行自动装配。如果有多个合适的候选对象,可以使用`@Qualifier`注解指定具体的bean名称。
- 示例:
@Resource
private UserService userService;
Spring将会自动寻找名为`userService`的`UserService`类型的bean,并将其注入到该字段中。
2. `@Resource`注解:
- `@Resource`是JavaEE标准中定义的注解,也可以实现依赖注入的功能。
- `@Resource`既可以根据名称进行自动装配,也可以根据类型进行自动装配,具备更强的灵活性,默认按照名称进行装配。
- 示例:
@Resourceprivate UserService userService;
@Resource`将会根据字段名称`userService`来查找并注入对应的bean。
两者的使用场景和功能类似,但在具体实现细节和使用上有一些差异。一般来说,如果项目使用的是Spring框架,推荐使用`@Autowired`注解;如果是JavaEE标准的项目,可以使用`@Resource`注解。当然,在实际使用中也可以根据具体需求选择合适的注解。
2.区别
`@Autowired`和`@Resource`注解的区别如下:
1. 来源:`@Autowired`是Spring框架提供的注解,而`@Resource`是JavaEE标准中定义的注解。
2. 自动装配方式:`@Autowired`按照类型进行自动装配,默认情况下要求依赖对象必须存在。如果存在多个匹配的bean,可以使用`@Qualifier`注解指定具体的bean名称。而`@Resource`默认按照名称进行自动装配,可以根据`name`属性指定特定的bean名称,也可以根据`type`属性进行按类型查找。
3. 包含范围:`@Autowired`只能用于字段、构造方法、Setter方法或者任意方法上。而`@Resource`既可以标注在字段上,也可以标注在setter方法上。
4. 引入的包:`@Autowired`需要导入`org.springframework.beans.factory.annotation.Autowired`包,而`@Resource`需要导入`javax.annotation.Resource`包。
5. 注解来源:`@Autowired`是Spring框架自带的注解,不依赖于JavaEE环境。而`@Resource`是JavaEE标准中定义的注解,它依赖于JavaEE环境。
综上所述,`@Autowired`和`@Resource`注解在实现依赖注入功能上有些许差异。`@Autowired`更加强调按照类型进行自动装配,而`@Resource`更加灵活,既可以按照名称进行自动装配,也可以按照类型进行自动装配。在使用上,如果是Spring框架的项目,一般推荐使用`@Autowired`注解;如果是JavaEE标准的项目,可以使用`@Resource`注解。但实际选择可以根据具体需求和个人偏好来确定。
五,总结
本文从IOC和DI的概念、区别以及具体实现方式入手,介绍了Spring框架中实现依赖注入的基本原理、好处和常见实现方式,最后对比了@Autowired和@Resource注解的区别和使用场景。总体来说,IOC和DI是Spring框架的核心特性,通过容器管理和注入对象之间的依赖关系,极大地提高了代码的灵活性、可维护性和可重用性。同时,根据具体需求和项目结构,选择合适的注解和实现方式可以更好地实现依赖注入的功能,提升开发效率和代码质量。
相关文章:
深入浅出讲解Spring IOC和DI的区别
Spring IOC和DI的区别 一,介绍 前言 很多人都会把ioc和di说成同一个东西,其实IOC和DI虽然在概念上可以笼统地视为同一事物,但其本质上存在区别。IOC(Inverse of Control,控制反转)从容器的角度描述&#…...
文件操作 IO
文件(File) 狭义的文件: 指的是硬盘上的文件和目录 广义的文件: 泛指计算机中很多软硬件资源(操作系统中把很多硬件和软件资源抽象成了文件, 按照文件的方式同意管理) 本章内容只讨论狭义的文件 路径 绝对路径: 以c: , d: 盘符开头的路径相对路径: 以当前所在的目录为基准(…...
ARouter - 组件化通信方案
官网 https://github.com/alibaba/ARouter/blob/master/README_CN.md 项目简介 一个用于帮助 Android App 进行组件化改造的框架 —— 支持模块间的路由、通信、解耦 功能介绍 支持直接解析标准URL进行跳转,并自动注入参数到目标页面中支持多模块工程使用支持添…...
Linux中常见的权限问题
目录 前言1. 目录权限2. umask3. 粘滞位结语 前言 在了解完上一篇文章 Linux权限的理解与操作 之后,还有一些比较常见的权限问题需要我们去了解。其中包括目录的权限,umask 以及 粘滞位的使用。 1. 目录权限 问题一:进入一个目录࿰…...
【技术分享】RK356X Ubuntu 推流USB摄像头
本文适用与触觉智能所有RK356X ubuntu系统的主板。 IDO-SBC3566基于瑞芯微RK3566研发的一款高性能低功耗的智能主板,采用四核A55,主频高达1.8GHz,专为个人移动互联网设备和AIOT设备而设计,内置了多种功能强大的嵌入式硬件引擎,为…...
介绍一下rabbitMq应用场景
任务队列:RabbitMQ可以将待处理的任务放入队列中,再由多个工作进程异步地执行这些任务。 日志处理:RabbitMQ可以通过发布-订阅模式将日志消息分发到多个消费者,并可以灵活地控制消息的优先级和过滤条件。 实时消息处理ÿ…...
IoT 物联网共享充电桩场景中设备资产定位和地理围栏开发实践
基于经纬度的设备资产定位和地理围栏在物联网场景中应用广泛 01 物联网 GEO 场景架构方案 首先,IoT 终端设备通过卫星定位模块获取当前经纬度;然后,将坐标信息实时上报到物联网平台;最后,存储到 Redis GEO 数据库中。 …...
【Qt进阶之自定义控件】使用QListWidget实现自定义Item效果
目的 Q:如何在Qt库的基础上,实现自定义控件呢? A:根据官方文档回答,就是继承需实现的控件,然后实现自定义功能。 以下是实现QListWidget控件的自定义item。 先看下最终效果是如何: listItem 主…...
【iOS】UITableView总结(Cell的复用原理、自定义Cell、UITableViewCell协议方法)
UITableView 列表的特点: 数据量大样式较为统一通常需要分组垂直滚动通常可视区只有一个 -> 视图的复用 UITableViewDataSource UITableView作为视图,只负责展示,协助管理,不管理数据 需要开发者为UITableView提供展示所需…...
shell之常见网络命令介绍
shell之常见网络命令介绍 1)ifconfig 用于配置网络接口。可以用于开启、关闭和设置网络接口的参数,如IP地址、子网掩码、MAC地址等。 ifconfig eth0 192.168.1.1 netmask 255.255.255.0 up上述命令将设置eth0网络接口的IP地址为192.168.1.1,子…...
Android屏幕刷新机制
基础知识 CPU运行在Android设备上的中央处理器(Central Processing Unit)是Android设备的核心组件之一,负责执行计算和控制设备的各种操作。 Android设备上的CPU通常采用ARM架构,如ARM Cortex-A系列处理器。这些处理器具有高性能…...
Python学习第3天-第一个Python程序
文章目录 前言一、创建项目二、创建程序总结 前言 下面给大家展示下经典的Hello World! 一、创建项目 二、创建程序 print("Hello World!")总结 回到顶部 学习网站 欢迎来到Python的世界!...
Golang网络
golang游戏服务器框架 在Go语言中,有许多优秀的游戏服务器框架,以下是一些比较流行的框架: Leaf:一个轻量级的游戏服务器框架,支持多进程、分布式、热更新等特性。它提供了一些常用的组件,如网络层、定时器、数据库等等,可以帮助开发者快速构建游戏服务器。go-ethereum…...
[swift刷题模板] 树状数组(BIT/FenwickTree)
[TOC]([swift刷题模板] 树状数组(BIT/FenwickTree) ) 一、 算法&数据结构 1. 描述 [python刷题模板] 树状数组 二、 模板代码 1. 单点赋值(增加),区间求和(PURQ) 例题: 307. 区域和检索 - 数组可修改 class BIT {var c: [Int]var n: Int init(_ n: Int){c…...
CUDA学习笔记(三)CUDA简介
本篇博文转载于https://www.cnblogs.com/1024incn/tag/CUDA/,仅用于学习。 前言 线程的组织形式对程序的性能影响是至关重要的,本篇博文主要以下面一种情况来介绍线程组织形式: 2D grid 2D block 线程索引 矩阵在memory中是row-major线性…...
RK3568笔记三:基于ResNet18的Cifar-10分类识别训练部署
若该文为原创文章,转载请注明原文出处。 本篇文章参考的是野火-lubancat的rk3568教程,本篇记录了在正点原子的ATK-DLK3568部署。 一、介绍 ResNet18 是一种卷积神经网络,它有 18 层深度,其中包括带有权重的卷积层和全连接层。它…...
块状数据结构学习笔记
分块 分块的思想和珂朵莉树很类似,就是把原序列分成若干个块,对块进行操作的奇妙思想。复杂度通常带根号。分块的块长也有讲究,通常对于大小为 n n n 的数组,取距离 n \sqrt n n 最近的 2 2 2 的幂数或直接取 n \sqrt n n…...
DOM4J解析.XML文件
<?xml version"1.0" encoding"utf-8" ?> <books><book id"SN123123413241"><name>java编程思想</name><author>华仔</author><price>9.9</price></book><book id"SN1234…...
黑豹程序员-架构师学习路线图-百科:MVC的演变终点SpringMVC
MVC发展史 在我们开发小型项目时,我们代码是混杂在一起的,术语称为紧耦合。 如最终写ASP、PHP。里面既包括服务器端代码,数据库操作的代码,又包括前端页面代码、HTML展现的代码、CSS美化的代码、JS交互的代码。可以看到早期编程就…...
二、BurpSuite Intruder暴力破解
一、介绍 解释: Burp Suite Intruder是一款功能强大的网络安全测试工具,它用于执行暴力破解攻击。它是Burp Suite套件的一部分,具有高度可定制的功能,能够自动化和批量化执行各种攻击,如密码破解、参数枚举和身份验证…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
前端开发面试题总结-JavaScript篇(一)
文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包(Closure)?闭包有什么应用场景和潜在问题?2.解释 JavaScript 的作用域链(Scope Chain) 二、原型与继承3.原型链是什么?如何实现继承&a…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)
目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 编辑编辑 UDP的特征 socke函数 bind函数 recvfrom函数(接收函数) sendto函数(发送函数) 五、网络编程之 UDP 用…...
【实施指南】Android客户端HTTPS双向认证实施指南
🔐 一、所需准备材料 证书文件(6类核心文件) 类型 格式 作用 Android端要求 CA根证书 .crt/.pem 验证服务器/客户端证书合法性 需预置到Android信任库 服务器证书 .crt 服务器身份证明 客户端需持有以验证服务器 客户端证书 .crt 客户端身份…...
