Java阶段三02
第3章-第2节
一、知识点
面向接口编程、什么是spring、什么是IOC、IOC的使用、依赖注入
二、目标
-
了解什么是spring
-
理解IOC的思想和使用
-
了解IOC的bean的生命周期
-
理解什么是依赖注入
三、内容分析
-
重点
-
了解什么是spring
-
理解IOC的思想
-
掌握IOC的使用
-
-
难点
-
理解IOC的思想
-
掌握IOC的使用
-
四、内容
1、Spring
1.1 简介
spring是分层的java SE/EE应用full-stack轻量级开源框架,以IOC(Inverse Of Control:控制反转)和AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层Spring MVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE企业级应用开源框架。
1.2 优势
-
开源免费的轻量级框架
-
低侵入式设计,代码污染极低
-
支持事务的处理,对框架整合的支持
-
以控制反转(IOC),面向切面编程(AOP)为内核
-
方便解耦,简化开发:将对象的创建交给spring 无需new
-
提供了展现层SpringMVC和持久层Spring JDBCTemplate以及业务层事务管理等众多企业级应用技术
-
能整合开源世界众多第三方框架和类库
1.3 引入依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.11.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version>
</dependency>
2、Ioc
2.1 概念
控制反转(IoC,Inversion of Control)是一个概念,是一种思想。指将传统上由程序代码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理。控制反转就是对对象控制权的转移,从程序代码本身反转到了外部容器。通过容器实现对象的创建,属性赋值,依赖的管理。
以前我们在代码中,使用new 构造方法创建对象,现在不用了, 由容器代替开发人员管理对象。
2.2 传统方式和ioc方式的区别
-
传统
我们要实现某一个功能或者说是完成某个业务逻辑时至少需要两个或以上的对象来协作完成,每个对象在需要使用他的合作对象时,自己均要使用像new object() 这样的语法来将合作对象创建出来,这个合作对象是由自己主动创建出来的,创建合作对象的主动权在自己手上,自己需要哪个合作对象,就主动去创建,创建合作对象的主动权和创建时机是由自己把控的,而这样就会使得对象间的耦合度高了,A对象需要使用合作对象B来共同完成一件事,A要使用B,那么A就对B产生了依赖,也就是A和B之间存在一种耦合关系,并且是紧密耦合在一起。
-
ioc
创建合作对象B的工作是由Spring来做的,Spring创建好B对象,然后存储到一个容器里面,当A对象需要使用B对象时,Spring就从存放对象的那个容器里面取出A要使用的那个B对象,然后交给A对象使用,至于Spring是如何创建那个对象,以及什么时候创建好对象的,A对象不需要关心这些细节问题(你是什么时候生的,怎么生出来的我可不关心,能帮我干活就行),A得到Spring给我们的对象之后,两个人一起协作完成要完成的工作即可。
下面用制造汽车需要引擎、轮胎等零件的场景解释含义
-
假设现在要生产汽车、货车、客车、出租车,它们都是使用【1代引擎】
代码如下:
public class EngineV1 {
private String name = "1代引擎";
public String getName() {return name;}
}
/*** 汽车*/
public class Car {
private String carName = "小汽车";
private EngineV1 engineV1;
public Car(EngineV1 engineV1) {this.engineV1 = engineV1;}
public void info() {System.out.println(carName + "使用的是" + engineV1.getName());}
}
/*** 货车*/
public class Van {
private String carName = "货车";
private EngineV1 engineV1;
public Van(EngineV1 engineV1) {this.engineV1 = engineV1;}
public void info() {System.out.println(carName + "使用的是" + engineV1.getName());}
}
测试
Car car = new Car(new EngineV1());
car.info();
Van van = new Van(new EngineV1());
van.info();
// 结果
// 小汽车使用的是1代引擎
// 货车使用的是1代引擎
总结:现在可以看出不管是汽车还是货车,都是依赖于【1代引擎】的,耦合度很高,没有【1代引擎】就没有这些车。假如我们还有很多其他类型的车都是依赖于【1代引擎】,有一天我想把所有的【1代引擎】换成 【2代引擎】我该怎么做?全局搜索【1代引擎】修改为 【2代引擎】,想想都有点麻烦。
-
我们需要换一种思路来实现,解决上述问题。
/*** 引擎接口*/
public interface IEngine {String getName();
}
public class EngineV1 implements IEngine{
private String name = "1代引擎";
public String getName() {return name;}
}
public class EngineV2 implements IEngine{
private String name = "2代引擎";
public String getName() {return name;}
}
/*** 汽车*/
public class Car {
private String carName = "小汽车";
// 现在不依赖于具体哪个引擎,直接对接引擎接口private IEngine engine;
public Car(IEngine engine) {this.engine = engine;}
public void info() {System.out.println(carName + "使用的是" + engine.getName());}
}
/*** 货车*/
public class Van {
private String carName = "货车";
private IEngine engine;
public Van(IEngine engine) {this.engine = engine;}
public void info() {System.out.println(carName + "使用的是" + engine.getName());}
}
测试
Car car = new Car(new EngineV1());
car.info();
Van van = new Van(new EngineV1());
van.info();
// 结果
// 小汽车使用的是1代引擎
// 货车使用的是1代引擎
Car car = new Car(new EngineV2());
car.info();
Van van = new Van(new EngineV2());
van.info();
// 结果
// 小汽车使用的是2代引擎
// 货车使用的是2代引擎
总结:代码中不再依赖于具体,而是依赖于抽象容器,即要针对接口编程,不针对实现编程。过去思维中想要什么依赖,需要自己去 “拉” 改为抽象容器主动 “推” 给你,你只管使用实体就可以了。这是依赖倒转 (DIP) 的一种表现形式。由原来的汽车依赖引擎转化成了引擎依赖引擎接口了,进行了反转。现在生产汽车的时候,给汽车什么引擎它就用什么引擎,汽车就脱离了只能用【1代引擎】绝对绑定形式了。
我们还可以接着优化,现在是使用引擎的时候我们手动去new的。假如项目中有很多的地方使用了【1代引擎】,要换成【2代引擎】,即把全部的new EngineV1()改成new EngineV2()。
-
针对上面的问题进行优化。我们可以先创建一个仓库出来,把引擎先创建好放在容器里面。车辆要用引擎的时候直接从仓库里面获取。
/*** 容器*/
public class Container {
private Map<String, Object> map = new HashMap<String, Object>();
public Container() {// 此处利用可以利用读取配置的方式,利用反射动态创建出对象map.put("engine", new EngineV1());}
public Object getBean(String name) {return map.get(name);}
}
测试
// 创建容器
Container container = new Container();
Car car = new Car((IEngine) container.getBean("engine"));
car.info();
Van van = new Van((IEngine) container.getBean("engine"));
van.info();
// 结果
// 小汽车使用的是1代引擎
// 货车使用的是1代引擎
现在要把【1代引擎】化成【2代引擎】,我们只需要修改容器里面的引擎即可,只要修改一处地方。
map.put("engine", new EngineV2());
上面的测试结果就变成了
// 创建容器
Container container = new Container();
Car car = new Car((IEngine) container.getBean("engine"));
car.info();
Van van = new Van((IEngine) container.getBean("engine"));
van.info();
// 结果
// 小汽车使用的是2代引擎
// 货车使用的是2代引擎
总结:这就是IOC要做的事情。把创建对象的过程交给spring管理,我们需要用的时候直接拿就行。
3、基本使用
3.1 方式一:配置文件
-
创建xml文件 resources/文件名.xml

-
创建类
-
xml配置
<!-- id:spring生成对象的时候,放到容器里面,会给每一个对象生成一个id,用于区分对象 --> <!-- class:告诉它使用哪个类 --> <bean id="student" class="com.company.eneity.Student"> -
获取对象
-
通过id获取
public static void main(String[] args) {// 生成spring容器// 读取spring的xml文件,根据内容生成对应的对象,放到容器里面ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");// 获取对象,传入id,通过id获取对象Student student = (Student) ctx.getBean("student");System.out.println(student); } -
通过类获取
public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");Student student1 = ctx.getBean(Student.class);System.out.println(student1); }
-
3.2 方式二:注解
-
创建类
// spring扫描到这个注解的时候,会自动生成对象 @Component public class Teacher {} -
配置xml的component-scan
<!-- 扫描包,会去扫描注解,有对应注解的会自动生成对象 --> <context:component-scan base-package="com.company"></context:component-scan> -
获取对象
@Component public class TeacherDao {private Teacher teacher;public void test(){System.out.println(teacher);} } ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml"); TeacherDao teacherDao = ctx.getBean(TeacherDao.class); teacherDao.test(); 3.3 bean的生命周期
spring默认的是单例对象可以通过scope修改
-
单例对象
scope="singleton"
创建bean的时候使用默认的无参构造函数
一个应用只有一个对象的实例,它的作用范围就是整个应用
生命周期
对象出生:当应用加载,创建容器时,对象就被创建
对象活着:只要容器在,对象一直活着
对象死亡:当应用卸载,销毁容器时,对象就被销毁了
测试
// 创建spring容器 // 创建容器的时候,对象已经生成 ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml"); // 获取对象只是从容器里面拿出来 Student student1 = (Student) ctx.getBean("student"); Student student2 = (Student) ctx.getBean("student"); System.out.println(student1 == student2); // 结果 true -
多例对象
scope="prototype"
每次访问对象时,都会被重新创建对象实例
生命周期
对象出生:当使用对象时,创建新的对象实例
对象活着:对象在使用中,对象就一直活着
对象死亡:当对象长时间不用,被java垃圾回收机制回收
测试
// 创建spring容器 // 创建容器的时候对象还没有生成 ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml"); // 获取对象的时候才创建对象 Student student1 = (Student) ctx.getBean("student"); Student student2 = (Student) ctx.getBean("student"); System.out.println(student1 == student2); // 结果 false
4、依赖注入
IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。
4.1 使用构造函数
前提:类中需要提供一个对应参数列表的构造函数
标签:constructor-arg
标签属性:
index:指定参数在构造函数参数列表中的索引位置
type:指定参数在构造函数中的数据类型
name:指定参数在构造函数中的名称,用这个找给谁赋值
value:它能赋的值是基本数据类型和String类型
ref:它能赋的值是其他bean类型,也就是说,必须得是在配置文件中配置过的bean
-
基本数据类型(数值类和字符串类)
基本数据类型直接用value赋值
<bean id="student" class="com.company.eneity.Student"><!-- constructor-arg调用有参否则函数,必须有写构造函数 --><constructor-arg name="name" value="张三"></constructor-arg><constructor-arg name="age" value="18"></constructor-arg> </bean> -
引用数据类型
引用数据类型使用ref赋值
<bean id="student" class="com.company.eneity.Student"><!-- constructor-arg调用有参否则函数,必须有写构造函数 --><constructor-arg name="name" value="张三"></constructor-arg><constructor-arg name="age" value="18"></constructor-arg><constructor-arg name="studentMarjor" ref="studentMarjor"></constructor-arg> </bean>
4.2 使用set赋值
标签:property
标签属性:
name:找的是类中set方法后面的部分
value:给属性赋值的是基本数据类型和String类型
ref:给属性赋值是其他bean类型的
-
基本数据类型
<bean id="student2" class="com.company.eneity.Student2"><!-- property调用set的方法,必须set方法 --><property name="name" value="张三"></property><property name="age" value="18"></property> </bean> -
引用数据类型
<bean id="student" class="com.company.eneity.Student"><property name="name" value="张三"></property><property name="age" value="18"></property><property name="studentMarjor" ref="studentMarjor"></property> </bean> <bean id="studentMarjor" class="com.company.eneity.StudentMarjor"><property name="name" value="软件工程"></property><property name="studentNum" value="80"></property> </bean>
5、小结
本章节中我们学习了什么是Spring,spring的优势是什么,为什么要用spring,同时学习了spring的一个核心功能IOC(控制反转),理解了控制反转的作用以及为什么要用控制反转,同时理解了什么是依赖注入,学会了通过XML文件配置IOC和不同方式的依赖注入。
下一节中,我们将会学习一些Spring的常用注解,学会使用注解进行开发,去理解注解开发和配置文件开发的区别和优势。
相关文章:
Java阶段三02
第3章-第2节 一、知识点 面向接口编程、什么是spring、什么是IOC、IOC的使用、依赖注入 二、目标 了解什么是spring 理解IOC的思想和使用 了解IOC的bean的生命周期 理解什么是依赖注入 三、内容分析 重点 了解什么是spring 理解IOC的思想 掌握IOC的使用 难点 理解IO…...
【Linux】掌握库的艺术:我的动静态库封装之旅
🌈个人主页:Yui_ 🌈Linux专栏:Linux 🌈C语言笔记专栏:C语言笔记 🌈数据结构专栏:数据结构 🌈C专栏:C 文章目录 1.什么是库1.2 认识动静态库1.2.1 动态库1.2.2…...
UE5动画控制 基础
素材 mixamo先去选择一个character 点击下载 就这个下载下来 然后选几个animation, 记得勾选 把动作下载了 without skin就是只要动作 然后把他们放在一个文件夹里先 UE里导入 找一个文件夹,直接拖拽进来那个character的fbx,默认配置就…...
流畅!HTMLCSS打造网格方块加载动画
效果演示 这个动画的效果是五个方块在网格中上下移动,模拟了一个连续的加载过程。每个方块的动画都是独立的,但是它们的时间间隔和路径被设计为相互协调,以创建出流畅的动画效果。 HTML <div class"loadingspinner"><…...
linux命令之top(Linux Command Top)
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 本人主要分享计算机核心技…...
数据结构-希尔排序(ShellSort)笔记
看动画理解 【数据结构】八大排序(超详解附动图源码)_数据结构排序-CSDN博客 一 基本思想 先选定一个整数gap,把待排序文件中所有记录分成gap个组,所有距离为gap的记录分在同一组内,并对每一组内的元素进行排序。 然后将gap逐渐减小重复上…...
Junit + Mockito保姆级集成测试实践
一、做好单测,慢即是快 对于单元测试的看法,业界同仁理解多有不同,尤其是在业务变化快速的互联网行业,通常的问题主要有,必须要做吗?做到多少合适?现在没做不也挺好的吗?甚至一些大…...
软件项目管理要点
一.项目管理 1.盈亏平衡分析 销售额固定成本可变成本税费利润 当利润为0的时候就是盈亏平衡点。 2.范围管理 范围定义的输入包括:项目章程、项目范围管理计划、组织过程资产、批准的变更申请。 3.时间管理 项目时间管理中的过程包括活动定义、活动排序、活动的资…...
ESP8266 连接 MQTT 服务器EMQX 连接MQTTX
目录 1.先用有一台自己的云服务器 2. 使用FinalShell连接阿里云云服务器ECS 3.安装宝塔 4.在云服务器打开8888端口 5.使用外网面板地址打开宝塔面板 6.安装Docker 7.下载emqx 8.打开emqxWeb 界面 9.下载MQTTX 10.EMQX加一个客户端 11.开始通信 12.加入单片机ESP8266 …...
Python中如何处理异常情况?
1、Python中如何处理异常情况? 在Python中,处理异常情况通常使用try/except语句。try语句块包含可能会引发异常的代码,而except语句块包含处理异常的代码。如果try块中的代码引发了异常,控制流将立即转到相应的except块。 以下是…...
openpnp - 在openpnp中单独测试相机
文章目录 openpnp - 在openpnp中单独测试相机概述笔记END openpnp - 在openpnp中单独测试相机 概述 底部相机的位置不合适, 重新做了零件,准备先确定一下相机和吸嘴的距离是多少才合适。 如果在设备上直接实验,那么拆装调整相机挺麻烦的。 准备直接在电…...
Spark窗口函数
1、 Spark中的窗口函数 窗口就是单纯在行后面加一个列 可以套多个窗口函数,但彼此之间不能相互引用,是独立的 窗口函数会产生shuffle over就是用来划分窗口的 (1) 分组聚合里面的函数,基…...
Idea、VS Code 如何安装Fitten Code插件使用
博主主页:【南鸢1.0】 本文专栏:JAVA 目录 编辑 简介 所用工具 1、Idea如何安装插件 1.idea下载插件 2.需要从外部下载然后在安装, 2、VS Code如何安装插件 总结 简介 Fitten Code是由非十大模型驱动的AI编程助手,它可以自动生成代…...
elasticsearch7.x在k8s中的部署
一、说明 二、思路 三、部署 1、建nfs服务器 2、建持久卷 3、部署elasticsearch 四、附件 ?pv.yaml内容 elasticsearch.yaml内容 一、说明 本文章内容主要的参考来源是https://www.cnblogs.com/javashop-docs/p/12410845.html,但参考文献中的elasticsearc…...
校园社团信息管理平台:Spring Boot技术实战指南
3系统分析 3.1可行性分析 通过对本校园社团信息管理系统实行的目的初步调查和分析,提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本校园社团信息管理系统采用SSM框架,JAVA作…...
【Linux】从内核角度理解 TCP 的 全连接队列(以及什么是 TCP 抓包)
文章目录 概念引入理解全连接队列内核方面理解Tcp抓包方法注意事项 概念引入 我们知道,TCP的三次握手是由TCP协议 自动处理的,建立连接的过程与用户是否进行accept无关,accept()的作用主要是为当前连接创建一个套接字,用于进行后…...
太速科技-712-6U VPX飞腾处理器刀片计算机
6U VPX飞腾处理器刀片计算机 一、产品概述 该产品是一款基于国产飞腾FT-2000四核处理器或D2000八核处理器的高性能6U VPX刀片式计算机。产品提供了可支持全网状交换的高速数据通道,其中P1、P2均支持1个PCIe x16 Gen3或2个PCIe x8 Gen3或4个PCIe x4 Gen3总…...
深度学习(八) TensorFlow、PyTorch、Keras框架大比拼(8/10)
一、深度学习框架概述 深度学习框架在当今人工智能和机器学习领域中占据着至关重要的地位。其中,TensorFlow 由 Google 开发,自 2015 年发布以来,凭借其灵活的计算图、自动微分功能以及跨平台支持等特点,迅速成为主流深度学习框架…...
thinkphp中命令行工具think使用,可用于快速生成控制器,模型,中间件等
在使用tp框架的时候tp内置了一个think的命令行工具, 这个工具可以帮助我们快速的生成控制器,模型,中间件的代码。 这个工具就和laravel中的 artisan 的作用都差不多,只是名称不同而已。 tp中常用的命令行工具: 1. 快…...
Discourse 是否支持手机注册
Discourse 能不能使用手机进行注册? 功能总结 简答来说,Discourse 不能使用手机注册,Discourse 也没有提供这个功能。 这个功能多是需要 SSO 来实现。 比如说华为的那个社区,他们自己做了一个自己的用户管理 SSO,然…...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
中医有效性探讨
文章目录 西医是如何发展到以生物化学为药理基础的现代医学?传统医学奠基期(远古 - 17 世纪)近代医学转型期(17 世纪 - 19 世纪末)现代医学成熟期(20世纪至今) 中医的源远流长和一脉相承远古至…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
