Spring IOC 容器:掌握 Spring 的核心技术
Spring 是一个非常流行和强大的 Java 开发框架,它可以帮助我们简化和优化 Java 项目的开发过程。Spring 的核心技术之一就是 IOC(Inversion of Control,控制反转),它可以实现对象之间的解耦,让对象的创建和管理由 Spring 容器来完成,而不是由对象自己或使用对象的类来完成。这样可以提高代码的可维护性和可扩展性,也可以方便地进行单元测试和依赖注入。
那么,Spring IOC 容器是如何工作的呢?本文将详细地介绍 Spring IOC 容器的原理和应用,掌握 Spring 的核心技术。
什么是 IOC?
IOC(Inversion of Control,控制反转)是一种设计思想,它的目的是实现对象之间的解耦,让对象的创建和管理由第三方(如 Spring 容器)来完成,而不是由对象自己或使用对象的类来完成。这样可以提高代码的可维护性和可扩展性。
为了理解 IOC 的含义,我们可以先看一个没有使用 IOC 的例子:
public class UserService {// UserService 依赖于 UserDaoprivate UserDao userDao = new UserDao();public void saveUser(User user) {// 调用 UserDao 的方法userDao.save(user);}
}
在这个例子中,UserService 类依赖于 UserDao 类,它需要在自己的内部创建 UserDao 的实例,并调用其方法。这样做有以下几个问题:
- UserService 和 UserDao 紧密地耦合在一起,如果 UserDao 的实现方式或者构造参数发生变化,UserService 也需要修改代码来适应。
- UserService 难以进行单元测试,因为它需要创建真实的 UserDao 实例,并依赖于数据库环境。
- UserService 无法灵活地替换 UserDao 的实现类,比如使用不同的数据库或者框架。
那么,如果使用了 IOC 怎么样呢?我们可以看下面的例子:
public class UserService {// UserService 依赖于 UserDao 接口private UserDao userDao;// 通过构造器或者 setter 方法注入 UserDao 的实现类public UserService(UserDao userDao) {this.userDao = userDao;}public void setUserDao(UserDao userDao) {this.userDao = userDao;}public void saveUser(User user) {// 调用 UserDao 的方法userDao.save(user);}
}
在这个例子中,UserService 类只依赖于 UserDao 接口,而不是具体的实现类。UserService 不需要在自己的内部创建 UserDao 的实例,而是通过构造器或者 setter 方法注入 UserDao 的实现类。这样做有以下几个优点:
- UserService 和 UserDao 松散地耦合在一起,如果 UserDao 的实现方式或者构造参数发生变化,UserService 不需要修改代码来适应。
- UserService 容易进行单元测试,因为它可以使用模拟(Mock)对象来替代真实的 UserDao 实例,并不依赖于数据库环境。
- UserService 可以灵活地替换 UserDao 的实现类,比如使用不同的数据库或者框架。
从上面的例子可以看出,使用了 IOC 后,UserService 不再主动控制 UserDao 的创建和管理,而是交给了第三方(如 Spring 容器)来完成。这就是控制反转的含义:将对象之间的控制权从主动方转移到被动方,从而实现对象之间的解耦。
什么是 Spring IOC 容器?
Spring IOC 容器是一个用于实现 IOC 的组件,它可以创建和管理对象,以及维护对象之间的依赖关系。Spring IOC 容器的主要功能有以下几个方面:
- 配置解析:Spring 通过 XML 或注解的方式来配置 Bean 的信息,如类名、属性、依赖等。Spring 会解析这些配置信息,并将其转换为 BeanDefinition 对象,用于描述 Bean 的元数据。BeanDefinition 对象会被注册到一个 BeanDefinitionRegistry 中,用于存储和管理 Bean 的配置信息。
- 反射机制:Spring 通过反射机制来创建 Bean 的实例,并通过反射或动态代理来调用 Bean 的方法。反射机制使得 Spring 可以在运行时动态地操作类和对象,而不需要提前知道它们的具体信息。
- 依赖注入:Spring 通过依赖注入(Dependency Injection,DI)来实现对象之间的依赖关系。依赖注入是指将一个对象所需要的其他对象(即依赖对象)通过配置或者代码的方式传递给该对象,而不是让该对象自己去创建或查找依赖对象。依赖注入有三种方式:构造器注入、setter 注入和接口注入。
- 容器管理:Spring 通过一个容器(Container)来管理 Bean 的生命周期和依赖关系。容器是一个抽象概念,它可以是一个接口或者一个类,用于提供 Bean 的创建、获取、销毁等操作。Spring 提供了两种类型的容器:BeanFactory 和 ApplicationContext。BeanFactory 是最基本的容器,它只提供了最简单的功能,如延迟加载、单例缓存等。ApplicationContext 是基于 BeanFactory 的扩展,它提供了更多的高级功能,如事件发布、资源加载、国际化等。
如何使用 Spring IOC 容器?
要使用 Spring IOC 容器,我们需要进行以下几个步骤:
- 创建 Java 类,并添加相应的注解或者编写 XML 配置文件来定义 Bean 的信息。
- 创建 Spring 容器,并加载配置文件或者扫描注解。
- 从 Spring 容器中获取或者注入所需的 Bean,并使用它们完成业务逻辑。
下面我们来看一个简单的例子:
// 创建一个 User 类
public class User {private String name;private int age;// 省略构造器、getter 和 setter 方法public void sayHello() {System.out.println("Hello, I am " + name + ", I am " + age + " years old.");}
}// 创建一个 UserService 类
public class UserService {// 注入 User 类型的 Bean@Autowiredprivate User user;public void greetUser() {// 调用 User 的方法user.sayHello();}
}// 创建一个测试类
public class Test {public static void main(String[] args) {// 创建一个 ApplicationContext 类型的容器,并加载配置文件ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");// 从容器中获取 UserService 类型的 BeanUserService userService = context.getBean(UserService.class);// 调用 UserService 的方法userService.greetUser();}
}
在这个例子中,我们创建了两个 Java 类:User 和 UserService。User 类表示用户的实体类,UserService 类表示用户的业务类。我们在 UserService 类中使用 @Autowired 注解来注入 User 类型的 Bean,这样就可以在 UserService 中使用 User 的方法。
然后我们创建了一个测试类,在测试类中我们创建了一个 ApplicationContext 类型的容器,并加载了配置文件 applicationContext.xml。在配置文件中,我们定义了 User 和 UserService 两个 Bean 的信息,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 定义一个 User 类型的 Bean --><bean id="user" class="com.example.User"><!-- 设置 User 的属性 --><property name="name" value="Tom"/><property name="age" value="20"/></bean><!-- 定义一个 UserService 类型的 Bean --><bean id="userService" class="com.example.UserService"><!-- 注入 User 类型的 Bean --><property name="user" ref="user"/></bean></beans>
在配置文件中,我们使用 <bean> 标签来定义 Bean 的信息,如 id、class、property 等。我们可以通过 id 属性来指定 Bean 的唯一标识符,通过 class 属性来指定 Bean 的全限定类名,通过 property 标签来设置 Bean 的属性。我们可以通过 value 属性来指定属性的值,通过 ref 属性来指定属性的引用。在这个例子中,我们定义了 user 和 userService 两个 Bean,并且将 user Bean 注入到 userService Bean 中。
最后,我们在测试类中从容器中获取 userService 类型的 Bean,并调用其方法。运行测试类,我们可以看到输出结果如下:
Hello, I am Tom, I am 20 years old.
这说明我们成功地使用了 Spring IOC 容器来创建和管理对象,并实现了对象之间的依赖注入。
总结
本文为介绍了 Spring IOC 容器的原理和应用,更好掌握 Spring 的核心技术。Spring IOC 容器可以帮助我们实现对象之间的解耦,让对象的创建和管理由 Spring 容器来完成,而不是由对象自己或使用对象的类来完成。这样可以提高代码的可维护性和可扩展性,也可以方便地进行单元测试和依赖注入。
相关文章:
Spring IOC 容器:掌握 Spring 的核心技术
Spring 是一个非常流行和强大的 Java 开发框架,它可以帮助我们简化和优化 Java 项目的开发过程。Spring 的核心技术之一就是 IOC(Inversion of Control,控制反转),它可以实现对象之间的解耦,让对象的创建和…...
python实现批量从excel列表显示图片网址中下载图片
遇到一个需求:给了一个excel表,里面有很多网址图片,要把图片下载到本地。手动操作的话就是在浏览器里输入网址,再图片另存为保存。这篇文章介绍一下使用python代码批量实现 第一步操作就是实现从网上下图片,这个用到了…...
java 单元测试Junit
所谓单元测试,就是针对最小的功能单元,编写测试代码对其进行正确性测试。为了测试更加方便,有一些第三方的公司或者组织提供了很好用的测试框架,给开发者使用。这里介绍一种Junit测试框架。Junit是第三方公司开源出来的࿰…...
Java中Timer和TimerTask的使用
这两个类使用起来非常方便,可以完成我们对定时器的绝大多数需求 Timer类是用来执行任务的类,它接受一个TimerTask做参数 Timer有两种执行任务的模式,最常用的是schedule,它可以以两种方式执行任务:1:在某个时间(Data),2:在某个固定的时间之后…...
计算机竞赛 机器视觉 opencv 深度学习 驾驶人脸疲劳检测系统 -python
文章目录 0 前言1 课题背景2 Dlib人脸识别2.1 简介2.2 Dlib优点2.3 相关代码2.4 人脸数据库2.5 人脸录入加识别效果 3 疲劳检测算法3.1 眼睛检测算法3.2 打哈欠检测算法3.3 点头检测算法 4 PyQt54.1 简介4.2相关界面代码 5 最后 0 前言 🔥 优质竞赛项目系列&#x…...
DFS寻找从s到t的所有路径
问题描述: 输入一个有向图,输出从s到t的所有路径的结点 输入: 3 3 0 1 1 2 0 2输出: 0 1 2 0 2 代码: #include<bits/stdc.h> using namespace std;const int N 103; vector<int>e[N];//用行为N的…...
分享!JetBrains IDE中的GitLab支持
GitLab是流行的基于git的软件开发和部署平台之一,虽然很长一段时间以来,所有基本git操作都已经可以通过GitLab实现,但GitLab集成仍是JetBrains社区的一大最热门请求。为此,JetBrains团队今年与GitLab联手提供了这种类型的集成。 …...
jq弹窗拖动改变宽高
预览效果 <div classtishiMask><div class"tishiEm"><div id"coor"></div><div class"topNew ismove"><span class"ismove">提示</span><p onclick"closeTishi()"></p&…...
时间不确定度在分布式系统中的说明
On the one hand 时间不确定度问题和影响在分布式系统中 说明 时钟不确定度(Clock Uncertainty)是指在分布式系统中,由于网络延迟、时钟漂移等因素导致系统中各个节点时钟的不同步现象。这种不同步可能会影响到分布式系统的一致性和正确性…...
VMware vCenter 从6.7跨版本升级至7.0U3N
本文尝试使用 vCenter Server Appliance 管理界面 (VAMI) 进行对vCenter Server Appliance7应用进行小版本升级,从6.7.0.47000升级到7.0.3.01600(7.0U3N)。 一、升级前的准备工作 1、检查当前运行环境(当前为6.7.0.47000&#x…...
大麦订单生成器最新版 大麦订单一键生成截图
1.可以一键添加,生成的假订单没有水印,界面也很真实。 2.在软件中输入生成的信息,这是产品信息,选择生成的产品图像,最后生成它。 后台一键生成,独立后台管理 教程:解压源码,修改数…...
如何对Map集合的key进行大小写转换?
工具类: ToUpperCaseKeyMapUtil.java public class ToUpperCaseKeyMapUtil {//对单一的mappublic static <T> Map<String, T> toUpperCaseKeyMap(Map<String, T> map) {if (map ! null) {List<String> mapKeyList new ArrayList<>…...
将函数实现放到CPP报“无法解析的外部符号...”,系VS Bug
发现一个现象,就是项目中有一个类,如果将函数实现全部放到头文件中,编译不报错,如果将函数实现放到CPP中则始终提示“无法解析的外部符号...”,考虑到放到头文件中能正常编译运行,显然这里不符合“无法解析…...
异步FIFO设计的仿真与综合技术(3)
概述 本文主体翻译自C. E. Cummings and S. Design, “Simulation and Synthesis Techniques for Asynchronous FIFO Design 一文,添加了笔者的个人理解与注释,文中蓝色部分为笔者注或意译。前文链接: 异步FIFO设计的仿真与综合技术…...
什么是区块链,解释区块链的原理和应用场景
1、什么是区块链,解释区块链的原理和应用场景。 区块链是一种分布式数据库,它由一系列按照时间顺序排列的数据块组成,并采用密码学方式保证不可篡改和不可伪造。区块链技术最初起源于比特币,作为比特币的底层技术,用于…...
使用bert进行文本二分类
构建BERT(Bidirectional Encoder Representations from Transformers)的训练网络可以使用PyTorch来实现。下面是一个简单的示例代码: import torch import torch.nn as nn from transformers import BertModel, BertTokenizer# Load BERT to…...
用Windows Installer CleanUp Utility 在windows server上面将软件卸载干净,比如SQLSERVER
这里写自定义目录标题 下载文件:Windows Installer CleanUp Utility。 通过以上工具可以将一个应用程序卸载干净。...
Java手写LinkedList和拓展
Java手写LinkedList和拓展 思维导图 #mermaid-svg-K0RTlFFvnikDRvqp {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-K0RTlFFvnikDRvqp .error-icon{fill:#552222;}#mermaid-svg-K0RTlFFvnikDRvqp .error-text{fill…...
机器学习(14)---逻辑回归(含手写公式、推导过程和手写例题)
逻辑回归 一、逻辑回归概述二、模型、策略和优化(手写)三、w和b的梯度下降公式推导四、例题分析4.1 题目4.2 解答 一、逻辑回归概述 1. 逻辑回归也称作logistic回归分析,是一种广义的线性回归分析模型,属于机器学习中的监督学习。…...
LLFormer 论文阅读笔记
Ultra-High-Definition Low-Light Image Enhancement: A Benchmark and Transformer-Based Method 这是南京大学在AAAI 2023发表的一篇AAAI2023 超高清图像暗图增强的工作。提出了一个超高清暗图增强数据集,提供了4K和8K的图片,同时提出了一个可用于暗图…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...
Modbus RTU与Modbus TCP详解指南
目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...
02.运算符
目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&:逻辑与 ||:逻辑或 !:逻辑非 短路求值 位运算符 按位与&: 按位或 | 按位取反~ …...
