【Spring框架】Spring核心思想IoC以及依赖注入DI详解
目录
- Spring框架
- 前言 服务端三层开发
- 表现层
- 业务层
- 持久层
- Spring框架的概述
- Spring框架的优点
- Spring核心——IoC
- 什么是IoC?O.o
- 什么是耦合度?
- 创建第一个IoC程序
- 导入必要依赖
- 编写接口和实现类
- 编写Spring核心配置文件
- 测试类进行测试
- Spring配置文件
- Bean对象的创建和销毁的两个属性配置
- 实例化Bean对象的三种方式
- DI依赖注入
- 属性的set方法注入值
- 属性构造方法方式注入值
- 数组,集合(List,Set,Map),Properties等的注入
- 多配置文件的加载方式
- 主配置文件中直接添加
- 工厂创建的时候直接加载多个配置文件
Spring框架
前言 服务端三层开发
表现层
表现层负责处理用户界面和用户交互。它接收用户的请求,进行初步处理后转发给业务层,并将业务层返回的数据呈现给用户。常见的表现层技术包括 Web 框架(如 Spring MVC、Struts)、前端框架(如 React、Vue.js)等。
- Servlet
- SpringMVC
- Struts
业务层
业务层是系统的逻辑核心,负责处理业务规则和业务流程。它接收来自表现层的请求,调用持久层进行数据操作,并返回处理结果给表现层。业务层通常包含服务类和服务接口,实现复杂的业务逻辑和事务管理。常见的业务层技术包括 Spring、Hibernate 等。
- service
- Spring
持久层
持久层负责数据的存储和检索,主要与数据库进行交互。它提供了数据访问对象(DAO)或仓库(Repository)来封装数据访问逻辑,确保数据的一致性和完整性。持久层通常使用 ORM(对象关系映射)框架(如 Hibernate、MyBatis)来简化数据库操作。
- JDBC
- MyBatis
- JDBC Template
Spring框架的概述
Spring是一个开放源代码的设计层面框架,它解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。Spring是于2003年兴起的一个轻量级的Java 开发框架,由Rod Johnson创建。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。
Spring是于2003 年兴起的一个轻量级的Java开发框架,由Rod Johnson在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。
它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。
Spring的核心是控制反转(IoC控制反转)和面向切面(AOP)。简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架。
Spring框架的优点
-
方便解耦,简化开发,Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理。
-
AOP编程的支持,Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能。(可扩展性)
-
声明式事务的支持,只需要通过配置就可以完成对事务的管理,而无需手动编程。
-
方便程序的测试,Spring对Junit4支持,可以通过注解方便的测试Spring程序。
-
方便集成各种优秀框架,Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts2、Hibernate、MyBatis、Quartz等)的直接支持。
-
降低JavaEE API的使用难度,Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低。
Spring核心——IoC
什么是IoC?O.o
IOC——Inverse of Control,控制反转,将对象的创建权力反转给Spring框架!!
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。如下图(来自百度百科)

那么涉及到第二个问题:
什么是耦合度?
可以看看这篇文章:聊聊什么是耦合度-CSDN博客,简而言之就是各个对象或者类或者是模块之间的依赖程度,然而我们并不希望我们的程序是一个高耦合度的程序,因为这样各个模块之间紧密相连,会导致可扩展性、可维护性变差。
我们希望我们的程序是低耦合高内聚的程序,也就是模块内部的元素依赖关系紧密,而模块之间并不存在很紧密的依赖关系,高内聚度的模块会使得代码更加清晰、易于理解和维护,同时可以提高代码的复用性。
创建第一个IoC程序
这里还是说一下我用到的工具:
- IDE:IntelliJ IDEA 2024.2.3
- Maven:3.9.8
导入必要依赖
<dependencies><!-- Spring核心 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</version></dependency><!-- 日志接口 --><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.2</version></dependency><!-- 日志核心 --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.12</version></dependency><!-- JUnit测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency>
</dependencies>
编写接口和实现类
// 接口类
public interface UserService {public void hello();
}// 实现类
public class UserServiceImpl implements UserService {@Overridepublic void hello() {System.out.println("Hello IOC!!!");}
}
编写Spring核心配置文件
在src目录下创建applicationContext.xml的配置文件,名称是可以任意的,但是一般都会使用默认名称。我们通过这个配置文件来实现我们IoC的核心操作:
<?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"><!--IOC管理bean--><!--一个bean相当于一个对象bean的意义是将该类的创建对象的权利授予spring容器,让spring容器来创建对象,--><bean id="userService" class="com.qcby.service.Impl.UserServiceImpl" />
</beans>
前面我们提到,Spring设计核心就是IoC,这里配置文件中就是在由我们的IoC容器创建对象,我们将由IoC容器管理的Java对象称为Spring Bean,我们可以在编译器的对应的类文件中看到一个小咖啡豆的标志

测试类进行测试
下面我们写一个最简单的测试方法来测试我们写好的UserServiceImpl实现类:
@Testpublic void run1(){// 使用Spring的工厂ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");// 通过工厂获得类:UserService userService = (UserService) applicationContext.getBean("userService");userService.hello();}
输出结果:

这里简单穿插一条题外话:Spring的默认设计模式是单例模式——单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点。感兴趣的可以看看这篇文章:一文带你彻底搞懂设计模式之单例模式!!由浅入深,图文并茂,超超超详细的单例模式讲解!!-CSDN博客,介绍的很详细不再过多介绍。
Spring配置文件
-
id属性:Bean起个名字,在约束中采用ID的约束,唯一,取值要求:必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号 id:不能出现特殊字符。
-
class属性:Bean对象的全路径。
-
scope属性:scope属性代表Bean的作用范围,其中的属性值如下:
取值范围 说明 singleton 默认值,单例模式 prototype 多例模式 request WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 request 域中 session WEB 项目中,Spring 创建一个 Bean 的对象,将对象存入到 session 域中 global session WEB 项目中,应用在 Portlet 环境,如果没有 Portlet 环境那么globalSession 相当于 session
Bean对象的创建和销毁的两个属性配置
说明:Spring初始化bean或销毁bean时,有时需要作一些处理工作,因此spring可以在创建和拆卸bean的时候调用bean的两个生命周期方法
-
init-method标签:当bean被载入到容器的时候调用init-method属性指定的方法
-
destroy-method标签:当bean从容器中删除的时候调用destroy-method属性指定的方法
实例化Bean对象的三种方式
-
默认是无参数的构造方法(默认方式,基本上使用)
<bean id="userService" class="com.qcby.service.Impl.UserServiceImpl" /> -
静态工厂实例化方式
/*** 静态工厂方式*/ public class StaticFactory {// 静态工厂方式public static UserService createUs(){System.out.println("通过静态工厂的方式创建UserServiceImpl对象...");// 编写很多业务逻辑 权限校验return new UserServiceImpl();}}<bean id="us" class="com.qcby.demo1.StaticFactory" factory-method="createUs" /> -
实例工厂实例化方式,因为类中的方法非静态,所以需要先实例化类,再去创建对象,因此得名(说实话这个一开始还真没注意到)
/*** 动态工厂方式*/ public class Dfactory {public UserService createUs(){System.out.println("实例化工厂的方式...");return new UserServiceImpl();}}<bean id="dfactory" class="cn.tx.demo1.Dfactory" /> <bean id="us" factory-bean="dfactory" factory-method="createUs" />
DI依赖注入
依赖注入(Dependency Injection)是在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件中!!这么说可能有点难懂,可以理解为:你的类中有很多属性,比如name、age等,我们需要给这些属性赋值,但是我们又不想通过调用构造器或者是调用setter()方法去赋值,这时我们就可以用DI,来给这些属性赋值,或者是创建依赖对象。
**依赖注入是实现控制反转的一种常见方式。**目的是处理依赖于对象的关系
属性的set方法注入值
编写实现类,其中包括要实现的对象或属性,最后通过配置文件调用setter()方法进行注入:
// 实现类
public class OrderServiceImpl implements OrderService {// 编写成员属性,一定需要提供该属性的set方法private OrderDao orderDao;// 一定需要提供该属性的set方法,IOC容器底层就通过属性的set方法方式注入值public void setOrderDao(OrderDao orderDao) {this.orderDao = orderDao;}private String name;private Integer age;public void setName(String name) {this.name = name;}public void setAge(Integer age) {this.age = age;}@Overridepublic void saveOrder() {System.out.println("业务层,保存订单,姓名:" + name + "-年龄:" + age);orderDao.saveOrder();}
}public class OrderDaoImpl implements OrderDao {@Overridepublic void saveOrder() {System.out.println("持久层:保存订单...");}}
编写配置文件:
<!--DI:依赖注入-->
<bean id="orderService" class="com.qcby.service.Impl.OrderServiceImpl"><!-- 将实例化的对象注入到orderDao --><property name="orderDao" ref="orderDao" /><property name="name" value="Ray" /><property name="age" value="23" />
</bean>
<!-- 这里先将OrderDaoImpl实例化,再注入到orderService中 -->
<bean id="orderDao" class="com.qcby.DAO.Impl.OrderDaoImpl"/>
<bean id="orderDao" class="com.qcby.DAO.Impl.OrderDaoImpl"/>这条语句其实就是创建对象,并在<property name="orderDao" ref="orderDao" />这里将对象用orderDao接口接收
编写测试方法:
@Test
public void run2(){// 使用Spring的工厂ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");// 通过工厂获得类:OrderService orderService = (OrderService) applicationContext.getBean("orderService");orderService.saveOrder();
}

属性构造方法方式注入值
编写类以及对应的带参的构造方法
public class Car {// 名称private String cname;// 金额private Double cmoney;public Car(String cname, Double cmoney) {this.cname = cname;this.cmoney = cmoney;}@Overridepublic String toString() {return "Car{" +"cname='" + cname + '\'' +", cmoney=" + cmoney +'}';}
}
编写配置文件,注入属性值:
<bean id="car" class="com.qcby.Demo.Car"><constructor-arg name="cname" value="Porsche"/><constructor-arg name="cmoney" value="40000000" />
</bean>
测试:
@Test
public void run3(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");Car car = (Car) applicationContext.getBean("car");System.out.println(car.toString());
}

数组,集合(List,Set,Map),Properties等的注入
编写实现类,实现对应属性:
public class CollectionBean {// 数组private String [] strs;public void setStrs(String[] strs) {this.strs = strs;}private List<String> list;public void setList(List<String> list) {this.list = list;}private Map<String,String> map;public void setMap(Map<String, String> map) {this.map = map;}private Properties properties;public void setProperties(Properties properties) {this.properties = properties;}@Overridepublic String toString() {return "CollectionBean{" +"strs=" + Arrays.toString(strs) +", list=" + list +", map=" + map +", properties=" + properties +'}';}
}
编写配置文件,注入值:
<!--给集合属性注入值-->
<bean id="collectionBean" class="com.qcby.Demo.CollectionBean"><property name="strs"><array><value>美美</value><value>小凤</value></array></property><property name="list"><list><value>熊大</value><value>熊二</value></list></property><property name="map"><map><entry key="aaa" value="老王"/><entry key="bbb" value="小王"/></map></property><property name="properties"><props><prop key="username">root</prop><prop key="password">123456</prop></props></property>
</bean>
编写测试方法:
@Test
public void run4(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");CollectionBean collectionBean = (CollectionBean) applicationContext.getBean("collectionBean");System.out.println(collectionBean.toString());
}

多配置文件的加载方式
一共两种方式:
主配置文件中直接添加
<import resource="applicationContext2.xml"/>
工厂创建的时候直接加载多个配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml","applicationContext2.xml");
相关文章:
【Spring框架】Spring核心思想IoC以及依赖注入DI详解
目录 Spring框架前言 服务端三层开发表现层业务层持久层 Spring框架的概述Spring框架的优点Spring核心——IoC什么是IoC?O.o什么是耦合度? 创建第一个IoC程序导入必要依赖编写接口和实现类编写Spring核心配置文件测试类进行测试 Spring配置文件Bean对象的…...
Java项目-基于springboot框架的智慧外贸系统项目实战(附源码+文档)
作者:计算机学长阿伟 开发技术:SpringBoot、SSM、Vue、MySQL、ElementUI等,“文末源码”。 开发运行环境 开发语言:Java数据库:MySQL技术:SpringBoot、Vue、Mybaits Plus、ELementUI工具:IDEA/…...
Python程序控制结构 if语句详解
前面我们已经详细介绍了Python编程基础入门:从风格到数据类型再到表达式 在编程中,控制结构决定了代码的执行顺序。Python提供了丰富的控制结构,可以帮助程序根据不同条件做出不同的决策和操作。本文将深入介绍Python中常见的控制结构——包…...
【ppq install】
简介 PPQ 是 Sensetime OpenPPL 团队开源的量化部署工具,经过量化的神经网络往往能够在端侧加速600%~800%,而在目前已经支持OpenPPL, TensorRT, SNPE, NXP, Metax等多个不同平台的量化模拟与网络部署。PPQ 不仅限于提供强大而先进的量化优化算法&#x…...
3DGS相关方法conda环境配置
环境:ubuntu22.04,cuda_11.7 conda create -n 3dgs python3.8 -y conda activate 3dgs python -m pip install --upgrade pip pip uninstall torch torchvision functorch tinycudann pip install torch2.1.2cu118 torchvision0.16.2cu118 torchaudio2…...
python画图|曲线动态输出
【1】引言 前序教程中的曲线动态输出,其实是把曲线按照左右移动的形式输出(波的传递形式)。 python画图|曲线动态输出基础教程_python 动态曲线-CSDN博客 但有些时候我们更期待的是曲线不移动,随着自变量的增加而输出因变量&am…...
电子商务类型
常见电子商务类型及其代表性的例子: B2B(Business to Business) 定义:B2B 模式是指企业与企业之间的商业交易。在这种模式下,企业通过电子商务平台相互提供产品或服务。 特点: 大宗交易:通常…...
vue elementui el-table实现增加行,行内编辑修改
需求: 前端进行新增表单时,同时增加表单的明细数据。明细数据部分,可进行行编辑。 效果图: <el-card><div slot"header"><span style"font-weight: bold">外来人员名单2</span><…...
1. Redis简介与安装
1.1 什么是Redis Redis(Remote Dictionary Server)是一个开源的、基于内存的数据结构存储系统,支持多种数据结构,如字符串、列表、集合、有序集合和哈希。它不仅能作为一个高效的缓存工具,还能作为消息队列、分布式锁和…...
Redis的持久化存储和集群管理操作
Redis 的持久化存储和集群 一、引言 Redis 是一个开源的内存数据结构存储系统,被广泛应用于缓存、消息队列、排行榜等场景。然而,由于数据存储在内存中,一旦服务器重启或出现故障,数据就会丢失。为了解决这个问题,Re…...
Auto-encoder(自编码器)
Auto-encoder(自编码器) 1 基本概念 自编码就和之前的cycle GAN的概念很像,假設你有非常大量的圖片,在 Auto-Encoder 裡面你有兩個 Network,一個叫做 Encoder,一個叫做 Decoder,他們就是兩個 N…...
Vue+sortable+el-table表格排序使用指南
前言 这两天遇到一个需求:在点击【设置优先级】的按钮后弹出关于玩法类型的table,点击【排序】按钮可以后可以进行排序。由于组内使用的组件库是 element-ui,那我首先就想到了使用 el-table组件,但奈何其版本原因不能相应的拖拽排…...
表数据删一半,为什么表文件大小不变?
参数innodb_file_per_table 这个参数设置为ON,表示每个表数据单独存在一个文件中,这时如果执行drop命令,系统会直接删除表文件。 这个参数设置为off时,所有表的数据和索引都存在共享的.ibdata文件,即使表删掉了&…...
MoCoOp: Mixture of Prompt Learning for Vision Language Models
文章汇总 当前的问题 1)数据集风格变化。 如图1所示,对于一个数据集,单个软提示可能不足以捕获数据中呈现的各种样式。同一数据集中的不同实例可能与不同的提示符兼容。因此,更**自然的做法是使用多个提示来充分表示这些变化**。 2)过拟合…...
YOLOv8 onnx 部署
本文是在win10系统下进行yolov8目标检测推理的过程记录。 yolov8 已经集成到OpenCV,可以通过两种方式调用,一种是直接通过OpenCV 调用,另外一种是通过onnx runtime(ort)调用。 1、安装cuda 、opencv 等依赖库,具体可以参考 Win1…...
在文件里引用目录文件下的静态资源图片不显示
问题:两种图片路径的指定方式,第一种能展示图片但第二种不能 两个 示例中,图片展示的差异。 在第一个示例中,图片路径是硬编码在 标签的 src 属性中的: <img src"../../assets/img/header01.png" style…...
vue使用 jsplumb 生成流程图
1、安装jsPlumb: npm install jsplumb 2、 在使用的 .vue 文件中引入 import { jsPlumb } from "jsplumb"; 简单示例: 注意:注意看 id 为"item-3"和"item-9"那条数据的连线配置 其中有几个小图片&#x…...
攻坚金融关键业务系统,OceanBase亮相2024金融科技大会
10月15-16日,第六届中新数字金融应用博览会与2024金融科技大会(简称“金博会”)在苏州工业园区联合举办。此次大会融合了国家级重要金融科技资源——“中国金融科技大会”,围绕“赋能金融高质量发展,金融科技创新前行”…...
《纳瓦尔宝典:财富和幸福指南》读书随笔
最近在罗胖的得到听书中听到一本书,感觉很有启发,书的名字叫《纳瓦尔宝典》,从书名上看给人的感觉应该财富知识类、鸡汤爆棚哪类。纳瓦尔,这个名字之前确实没有听说过,用一句话介绍一下,一个印度裔的硅谷中…...
C++ | STL | 侯捷 | 学习笔记
C | STL | 侯捷 | 学习笔记 文章目录 C | STL | 侯捷 | 学习笔记1 STL概述1.1 头文件名称1.2 STL基础介绍1.3 typename 2 OOP vs. GP3 容器3.1 容器结构分类3.2 序列式容器3.2.1 array测试深度探索 3.2.2 vector测试深度探索 3.2.3 list测试深度探索 3.2.4 forward_list测试深度…...
SDMatte+边缘精修效果展示:羽毛建模精度、纱布透光过渡、叶片脉络保留
SDMatte边缘精修效果展示:羽毛建模精度、纱布透光过渡、叶片脉络保留 1. 惊艳效果开场 想象一下这样的场景:你需要为一件羽毛饰品拍摄产品图,但无论怎么调整灯光和背景,羽毛边缘总是显得模糊不清;或者当你尝试抠出一…...
告别命令行恐惧:用RU.EXE快捷键玩转硬件诊断(附常用命令速查表)
告别命令行恐惧:用RU.EXE快捷键玩转硬件诊断(附常用命令速查表) 在工业计算机维护和硬件诊断领域,RU.EXE一直是资深工程师的秘密武器。但对于每天奔波在不同现场的技术支持人员来说,面对这个功能强大却界面复古的工具&…...
42-西门子1200伺服控制5轴程序 程序采用1200系列PLC,项目实现以下功能: (1)
42-西门子1200伺服控制5轴程序 程序采用1200系列PLC,项目实现以下功能: (1).三轴机械手联动取放料PTO脉冲定位控制台达B2伺服 (2).台达伺服速度模式应用扭矩模式应用实现收放卷 (3).…...
4 大平台 “免费拿” 玩法大拆解,看完不踩坑
现在很多平台都有 “0元领东西” 的活动,玩法不一样,难度也差很多。今天用大白话对比拼dd、淘b、京d、全能锦鲤,简单易懂,看完就知道该选哪个。一、各平台免费拿怎么玩?1. 拼dd(老牌砍价)玩法&a…...
Qwen3.5-4B-Claude-Opus实际作品:正则表达式语法树构建与匹配逻辑推演
Qwen3.5-4B-Claude-Opus实际作品:正则表达式语法树构建与匹配逻辑推演 1. 模型能力概述 Qwen3.5-4B-Claude-4.6-Opus-Reasoning-Distilled-GGUF是一个专注于逻辑推理和结构化分析的轻量级AI模型。作为Qwen3.5-4B的蒸馏版本,它在处理代码解释、算法分析…...
卡尔曼滤波+LQR实战:用Python手写一个LQG控制器(附Jupyter Notebook)
卡尔曼滤波LQR实战:用Python手写一个LQG控制器(附Jupyter Notebook) 在机器人控制和自动化系统设计中,LQG(Linear Quadratic Gaussian)控制是一种经典且强大的控制策略。它巧妙地将卡尔曼滤波的状态估计能力…...
数据库课程设计案例:基于深度感知的智能仓储管理系统
数据库课程设计案例:基于深度感知的智能仓储管理系统 每次路过大型物流仓库,看到那些高耸的货架和穿梭的叉车,我总会想,他们是怎么知道哪个货位是满的,哪个是空的?靠人工盘点?那得累死。靠传统…...
string字符串基础相关知识
课程要求1.string的三种创建方式2.string常用方法空格处理,空值判断,替换操作,字符串截取,字符串拆分,字符索引访问拼接与性能,删除操作3.理解 string 不可变性,能在循环拼接场景中使用 StringB…...
B端拓客号码核验:困局审视、技术革新与行业前行,氪迹科技法人股东号码核验系统,阶梯式价格
在B端拓客的全流程中,有效触达企业核心决策层是实现合作转化的关键,而法人、股东、董监高等群体的联系方式,則是搭建这一沟通链路的核心基础。号码核验作为拓客工作的前置核心环节,其筛选质量与效率,直接决定着拓客投入…...
C#实战:基于WebAPI与Modbus构建EMS核心采集服务
1. 为什么需要EMS核心采集服务? 在工业现场,我们经常会遇到几十台甚至上百台智能电表、传感器等设备需要监控。这些设备可能来自不同厂家,使用不同的通信协议,数据格式也各不相同。想象一下,如果每个设备都需要单独开发…...
