【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测试深度…...

接口测试中缓存处理策略
在接口测试中,缓存处理策略是一个关键环节,直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性,避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明: 一、缓存处理的核…...

【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...

Golang——7、包与接口详解
包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...

Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合
作者:来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布,Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明,Elastic 作为 …...