【JavaEE进阶】Spring核心与设计思想
文章目录
- 一. Spring框架概述
- 1. 什么是Spring框架
- 2. 为什么要学习框架?
- 3. Spring框架学习的难点
- 二. Spring 核心与设计思想
- 1. 什么是容器?
- 2. 什么是IoC?
- 3. Spring是IoC容器
- 4. DI(依赖注入)
- 5. DL(依赖查找)
一. Spring框架概述
1. 什么是Spring框架
我们通常所说的 Spring
指的是 Spring Framework
(Spring 框架),它是⼀个开源框架,有着活跃⽽庞⼤的社区,这就是它之所以能⻓久不衰的原因.Spring ⽀持⼴泛的应⽤场景,它可以让 Java 企业级的应⽤程序开发起来更简单.
⽤⼀句话概括 Spring: Spring 是包含了众多⼯具⽅法的IoC容器.
2. 为什么要学习框架?
因为学习框架相当于从“小作坊”到“工厂”的升级,小作坊什么都要自己做,工厂是组件式装配,特点就是高效。框架更加易⽤,简单且高效.
Servlet有以下痛点:
- 添加外部 jar 不⽅便,容易出错,比如添加了⼀个不匹配的外部 jar 版本。
- 运行和调试的时候需要配置 Tomcat 不⽅便。
- 发布不方便,Servlet 项目必须依靠外置的 Tomcat(外置的 Web 容器)运行。
- 路由配置不方便,⼀个访问地址对应⼀个 Servlet 类。
- …
而 Spring Boot 相比于 Servlet 具备以下优点:
- 快速添加外部 jar 包。
- 调试项目更方便,无需配置 Tomcat,点击“运行”按钮就可以直接运行项目,因为 Spring Boot
内置了 Tomcat 容器可直接运行,但是 Servlet 需外挂 Tomcat。 - 发布项目更加方便,无需配置 Tomcat,使用 java -jar 方式就可以发布。
- 对象自动装配。
- 添加路由更加方便,无需每个访问地址都添加⼀个类。
- …
3. Spring框架学习的难点
- 配置比较多。
- 需要⼤量的外部 jar 包,在下载时容易出错。
- 会涉及简单的软件⼯程的设计思想(分层思想:前后端的分层思想;后端工程的分层思想)。
- 知识点相对来说比之前的知识更加的分散,要仔细听才能搞懂各个知识点的逻辑关系。
- 要记的东西很多,所以要大量地重复练习才能记住,比如各种注解。
Spring框架基本学习应用路线:Spring全家桶
(Spring/Spring Boot/Spring MVC) -> MyBatis
-> Redis
等。
二. Spring 核心与设计思想
Spring 核心就是这么一句话:Spring 框架是包含了众多工具方法的 IoC 容器。
那么这句话怎么理解呢?什么是容器?什么又是 IoC?
1. 什么是容器?
容器是⽤来容纳某种物品的(基本)装置。 ——来⾃:百度百科
之前我们接触的容器有以下:
- List/Map -> 数据存储容器
- Tomcat -> Web 容器
Spring 是就一个 IoC
容器,它包含了许多的工具和方法.
2. 什么是IoC?
IoC : Inversion of Control
翻译成中⽂是“控制反转”的意思.这是一种思想,控制权反转,在 Java 的常规代码中,对象的生命周期,是由当前代码(程序员自己)控制的,而控制权反转就是对象的生命周期,不再由当前代码片段来控制,而是由 Spring
(IoC 容器)来控制.
举个🌰:
我们都知道汽车包含轮胎,底盘,车身等.现在我们要造一辆汽车,需要有车身,而车身需要依赖于底盘.而底盘依赖于轮胎.
传统的思想中,在造车的时候需要车身,于是就new
一个车身,而车身需要底盘,于是就再new
一个底盘,底盘需要轮胎,于是就再new
一个轮胎.
package oldCar;
//传统汽车制造
//汽车类
public class Car {//车身private Framework framework;public Car(){framework = new Framework();}public void init() {System.out.println("do car");// 汽车的组建依赖于车身framework.init();}
}
package oldCar;
//车身类
public class Framework {//底盘private Bottom bottom;public Framework(){bottom = new Bottom();}public void init() {System.out.println("do framework");// 车身的组建依赖于底盘bottom.init();}
}package oldCar;
//底盘类
public class Bottom {//车轮private Tire tire;public Bottom(){tire = new Tire();}public void init(){System.out.println("do Bottom");//底盘依赖于轮胎tire.init();}
}package oldCar;
//轮胎类
public class Tire {private int size = 17;//轮胎的尺寸public void init(){System.out.println("size -> " + size);}
}package oldCar;public class Test {public static void main(String[] args) {Car car = new Car();car.init();}
}
车轮为17寸的汽车制作完毕.但是上述代码中轮胎大小是写死的,随着时代发展,人们对车的需求量越来越大,个性化需求也会越来越多,这时候我们就需要加工多种尺寸的轮胎,此时就需要修改上述代码.我们需要给轮胎Tire
类的构造方法加上一个参数.由于底盘Bottom
类控制了Tire
类,那么底盘类的构造方法也需要加上一个参数.以此类推,Freamwork
和Car
类都需要在构造方法中加上一个参数.
package oldCar;
//传统汽车制造
//汽车类
public class Car {//车身private Framework framework;public Car(int size){framework = new Framework(size);}public void init() {System.out.println("do car");// 汽车的组建依赖于车身framework.init();}
}
package oldCar;
//传统汽车制造
//汽车类
public class Car {//车身private Framework framework;public Car(int size){framework = new Framework(size);}public void init() {System.out.println("do car");// 汽车的组建依赖于车身framework.init();}
}
package oldCar;
//传统汽车制造
//汽车类
public class Car {//车身private Framework framework;public Car(int size){framework = new Framework(size);}public void init() {System.out.println("do car");// 汽车的组建依赖于车身framework.init();}
}package oldCar;
//轮胎类
public class Tire {private int size = 17;//轮胎的尺寸public Tire(int size) {this.size = size;}public void init(){System.out.println("size -> " + size);}
}
package oldCar;public class Test {public static void main(String[] args) {Car car = new Car(20);car.init();}
}
车胎尺寸为20寸的汽车制作好了.此时如果需要定制不同轮胎大小的尺寸,只需要改动狗仔Cae对象传入的参数即可.但是,如果再加上一个需求,改变车身颜色,那我们又要加三叔,此时就意味着和上述代码一样修改每一层的代码,整个调用链上的代码都需要修改.
上述代码耦合度就太高了.为了解决这个问题,我们可以使用loC
的思想来实现代码,将控制权交出去,也就是说,IoC
模式下,我们不再自己构造创建对象.当我们需要轮胎Tire
类时,你就给我传一个Tire
对象,我们不去new一个Tire对象了,这样的话,就算在Tire
类加参数也只需要改动Tire类的构造方法与相关执行方法与属性,顶多再改一下Tire对象的创建,同理其他类也一样,将对象作为参数传入到上级类的构造方法中去就行了,但此时其他类是不需要修改的,这个过程也叫做传入或注入。
由于我们创建Car时需要Framework,所以先要实例一个Framework对象,同理实例一个Framework对象需要Bottom对象,那么需先实例一个Bottom对象,一样,在实例Bottom对象之前需要实例一个Tire对象,于是需要先后创建Tire对象,Bottom对象,Framework对象后才能创建一个Car对象,我们可以得到如下的代码:
package newCar;public class Car {// 汽车的组建依赖于车身的组建private Framework franmework;public Car(Framework franmework) {this.franmework = franmework;}public void init() {System.out.println("do car...");franmework.init();}
}package newCar;public class Framework {// 车身的组建依赖于底盘private Bottom bottom;public Framework(Bottom bottom) {this.bottom = bottom;}public void init() {System.out.println("do franmework");bottom.init();}
}package newCar;public class Bottom {// 底盘的组建依赖于轮胎private Tire tire;public Bottom(Tire tire) {this.tire = tire;}public void init() {System.out.println("do bottom...");tire.init();}
}package newCar;public class Tire {private int size = 17;private String color = "黑色";public Tire(int size, String color) {this.size = size;this.color = color;}public void init() {System.out.println("size -> " + size);System.out.println("color->" + color);}
}package newCar;public class IOCDemo {// 这里的内容包含就相当于是 IoC 容器做的事情// 对象的生命周期控制权就翻转给 IoC 容器了, 不再由程序员控制private Tire tire;private Bottom bottom;private Framework framework;public Car car;public IOCDemo() {tire = new Tire(17, "红色");bottom = new Bottom(tire);framework = new Framework(bottom);car = new Car(framework);}
}package newCar;/*** 模拟 IoC 容器*/
public class Test {public static void main(String[] args) {// 直接使用, 创建就交给IoC了IOCDemo ioc = new IOCDemo();Car car = ioc.car;car.init();}
}
此时如果要变需求,需要加参数或减少参数,IoC 的代码只需改动两处代码即可, 整个调用链是不用做任何改变的, 达到了解耦的目的。
在传统的代码中对象创建顺序是:Car -> Framework -> Bottom -> Tire
改进之后解耦的代码的对象创建顺序是:Tire -> Bottom -> Framework -> Car
到这里我们就可以发现,传统的代码类创建顺序是反着的,Car 控制 FrameWork,FrameWork 控制着 Bottom,Bottom 控制着 Tire;而改进之后的控制权发生了反转,是下层将对象注入到当前对象当中,下级的控制权不再由上级控制了,下级在发生改变时会将改变完成后的对象注入上级,这样上级就是不受影响的,这就是 IoC 的实现思想。
所以 IoC 有以下的优点:对象(Bean)的生命周期交给 IoC 框架维护,作为程序员无需关注,说白了就是程序员不需要关注对象创建、销毁时机以及对象的依赖关系,这些工作加个 IoC 框架(也就是 Spring)做就行,实现了代码的解耦,对象的使用更加方便高效。
3. Spring是IoC容器
Spring 框架就是包含了多个工具方法的 IoC
容器,既然是容器,那它就有存和取的功能,这也是 Spring 最核心的两个功能:
- 将 Bean(对象)存储到 Spring 容器中。
- 将 Bean(对象)从 Spring 容器中取出来。
将对象存放到容器有什么好处呢?
将对象存储到 IoC 容器相当于我们将所有可能用到的工具制作好都放到仓库,当我们需要使用时直接取即可,用完归还仓库;而 new 对象的方式相当于我们每次需要用工具的时候现场制作,制作完了扔掉,下次需要的时候重新做。
Spring 是⼀个 IoC 容器,说的是对象的创建和销毁的权利都交给 Spring 来管理了,它本身⼜具备了存储对象和获取对象的能力。
4. DI(依赖注入)
DI,即Dependency Injection
,依赖注入。
所谓依赖注⼊,就是由 IoC 容器在运行期间,动态地将某种依赖关系注入到对象之中,在pom.xml
有一个依赖项,就是用来导入外部的资源,而这里的依赖注入,导入的不是外部的资源,而是对象;当某个 Java 实例需要另一个 Java 实例时,创建被调用者的工作不是由调用者实现,而是由 Spring 容器来完成,然后注入调用者,因此称为依赖注入。
IoC 与 DI 的区别是什么?
依赖注入(DI)和控制反转(IoC)是从不同的角度的描述的同⼀件事情,就是指通过引入 IoC 容器,利用依赖关系注入的方式,实现对象之间的解耦。
IoC 是“目标”也是⼀种思想,而目标和思想只是⼀种指导原则,最终还是要有可行的落地方案,而 DI 就属于具体的实现;也就是说,IoC 是一种思想,而 DI 是 IoC 的一种实现。
5. DL(依赖查找)
DL,即Dependency Lookup
,依赖查找,也是 IoC的一种实现。
依赖查找和依赖注入的区别在于,依赖注入是将依赖关系委托给容器,由容器来管理对象之间的依赖关系,容器外部是不关心这种依赖关系的,需要时由容器判断提供什么;而依赖查找是由对象自己来查找它所依赖的对象,容器只负责管理对象的生命周期,也就是说此时需要容器外部自己确定要容器提供哪种依赖关系;两者之间是主动和被动的区别。
相关文章:

【JavaEE进阶】Spring核心与设计思想
文章目录 一. Spring框架概述1. 什么是Spring框架2. 为什么要学习框架?3. Spring框架学习的难点 二. Spring 核心与设计思想1. 什么是容器?2. 什么是IoC?3. Spring是IoC容器4. DI(依赖注入)5. DL(依赖查找) 一. Spring框架概述…...
实习周记第三周
第二周总结 第二周主要是做了一些PC端细节内容。大的地方改的不多,但是小的细节蛮多。 值得一提的是,第二周做的微信小程序,改了很多逻辑。改逻辑需要与后端进行联调,收获很大,思路也愈发清楚。 记录做了什么是好习…...

11. 使用tomcat中碰到的一些问题
文章目录 问题一:Tomcat的startup.bat启动后出现乱码问题二:一闪而退之端口占用问题三:非端口问题的一闪而退问题四:服务器的乱码和跨域问题问题五: 在tomcat\webapps\下创建文件夹为什么tomcat重启就会丢失问题六:Tom…...
C++解决TCP粘包
目录 TCP粘包问题TCP客户端TCP服务端源码测试 TCP粘包问题 TCP是面向连接的,面向流的可靠性传输。TCP会将多个间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包发送,这样一个数据包里就可能含有多个消息的数据&#…...

最长快乐前缀——力扣1392
文章目录 题目描述KMP题目描述 KMP class Solution {public:string longestPrefix(string s) {int n = s...
使用java.util.List的containsAll()方法可能导致的问题
今天在偶然之间发现了一个bug,原因居然是使用了containsAll()方法,这个问题很简单,看以下代码就能发现很大的问题。 package collection;import java.util.ArrayList; import java.util.List;/*** author heyunlin* version 1.0*/ public cl…...

在线文本转语音播放 (TTS)
具体请前往:在线文本转语音播放(TTS)...
OPTEE之ARM安全扩展
目录 一、BTI(Branch Target Identification) 二、如何使能OP-TEE core的BTI 三、如何使能TA的BTI 一、BTI(Branch Target Identification) 分支目标识别(BTI)是ARMv8.5(及Armv9.0)扩展,它为间接分支及其目标提供了控制流完整性(CFI)保护,从而有助于限…...

Vue [Day4]
组件的三大组成部分 组件的样式冲突 scoped <style scoped></style>data 是一个函数 components/BaseButton.vue <template><div class"BaseButton"><button click"count--">-</button><span>{{ count }}</…...
google chrome 官方下载
官方渠道: 1、链接直接打开就可以下载,最新版实时更新。 32位(x86):https://dl.google.com/tag/s/installdataindex/update2/installers/ChromeStandaloneSetup.exe 64位(x64):htt…...

Misc取证学习
文章目录 Misc取证学习磁盘取证工具veracryto挂载fat文件DiskGenius 磁盘取证例题[RCTF2019]disk 磁盘[](https://ciphersaw.me/ctf-wiki/misc/disk-memory/introduction/#_2)内存取证工具volatility 内存取证例题数字取证赛题0x01.从内存中获取到用户admin的密码并且破解密码 …...
vue打包到jar资源访问被shiro拦截
1.shiro放发对静态资源的拦截// filterMap.put("/202307171550/**", "anon"); // filterMap.put("/config/**", "anon"); // filterMap.put("/index.html", "anon"); 2.装载资源访问 priva…...
选择排序(指针法)
描述 用选择法对10个整数排序。 输入 输入包含10个整数,用空格分隔。 输出 输出排序后的结果,用空格分隔。 输入样例 1 3 1 4 1 5 9 2 6 5 3 输出样例 1 1 1 2 3 3 4 5 5 6 9 输入样例 2 2 4 6 8 10 12 14 16 18 20 输出样例 2 2 4 6 8 1…...

8.6 day07 休息+剑指offer
文章目录 06从尾到头打印链表03数组中重复的数字04二维数组中的查找05 替换空格06重建二叉树背英语单词,看了二十页 06从尾到头打印链表 从尾到头遍历链表 方法一就是用栈来辅助,栈的结构是先进后出的,将链表中的元素加入到栈中去࿰…...

K8S系列文章 之 容器存储基础 Volume
Volume Volume是容器数据卷。我们经常创建删除一些容器,但有时候需要保留容器中的一些数据,这时候就用到了Volume。它也是容器之间数据共享的技术,可以将容器中产生的数据同步到本地。实际就是把容器中的目录挂载到运行着容器的服务器或个人…...

【CHI】架构介绍
Learn the architecture - Introducing AMBA CHI AMBA CHI协议导论--言身寸 1. AMBA CHI简介 一致性集线器接口(CHI)是AXI一致性扩展(ACE)协议的演进。它是Arm提供的高级微控制器总线架构(AMBA)的一部分。…...

hcip的ospf综合实验
题目 拓扑图 IP地址分配及环回 R1 < Huawei>sy Enter system view, return user view with CtrlZ. [Huawei]sysname r1 [r1]int g0/0/0 [r1-GigabitEthernet0/0/0]ip add 172.16.0.1 27 Aug 6 2023 19:03:33-08:00 r1 %%01IFNET/4/LINK_STATE(l)[0]:The line protocol I…...

AP5179 高端电流采样降压恒流驱动IC SOP8 LED车灯电源驱动
产品描述 AP5179是一款连续电感电流导通模式的降压恒流源,用于驱动一颗或多颗串联LED输入电压范围从 5 V 到 60V,输出电流 最大可达 2.0A 。根据不同的输入电压和外部器件, 可以驱动高达数十瓦的 LED。内置功率开关,采用高端电流…...
vue3+vite项目配置ESlint、pritter插件
配置ESlint、pritter插件 在 Vue 3 Vite 项目中,你可以通过以下步骤配置 ESLint 和 Prettier 插件: 安装插件: 在项目根目录下,打开终端并执行以下命令安装 ESLint 和 Prettier 插件: npm install eslint prettier e…...

K8S kubeadm搭建
kubeadm搭建整体步骤 1)所有节点进行初始化,安装docker引擎和kubeadm kubelet kubectl 2)生成集群初始化配置文件并进行修改 3)使用kubeadm init根据初始化配置文件生成K8S的master控制管理节点 4)安装CNI网络插件&am…...

大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...

通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...

STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...