当前位置: 首页 > news >正文

14、缓存预热+缓存雪崩+缓存击穿+缓存穿透

缓存预热+缓存雪崩+缓存击穿+缓存穿透

● 缓存预热、雪崩、穿透、击穿分别是什么?你遇到过那几个情况?
● 缓存预热你是怎么做到的?
● 如何避免或者减少缓存雪崩?
● 穿透和击穿有什么区别?它两一个意思还是截然不同?
● 穿透和击穿你有什么解决方案?如何避免?
● 加入出现了缓存不一致,你有哪些修补方案?

1、缓存预热
在这里插入图片描述
2、缓存雪崩
发生原因
● Redis主机挂了,Redis全盘崩溃,偏硬件运维。
● Redis中有大量key同时过期大面积失效,偏软件开发。
预防+解决
● Redis中key设置为永不过期or过期时间错开
● Redis缓存集群实现高可用
○ 主从+哨兵
○ Redis Cluster
○ 开启Redis持久化机制RDB/AOF,尽快恢复缓存集群
● 多缓存结合预防雪崩
○ ehcache本地缓存+redis缓存
● 服务降级
○ Hystrix或者案例sentinel限流&降级

3、缓存穿透
发生原因
请求去查一条记录,先查Redis无,后查MySQL无,都查不到该条记录,但是请求每次都会打到数据库上面去,导致后台数据库压力暴增,这种就是缓存穿透。
简单来说就是本来无一物,两库都没有,既不在Redis缓存库,也不再MySQL,数据库存在被多次暴击风险

解决方案
在这里插入图片描述

方案一:空对象缓存或者缺省值
一般正常情况下使用回写增强:mysql也查不到的话就让redis存入刚刚查不到的key并保护mysql,第一次来查询没有查询到,redis和mysql都没有,返回null给调用者,但是增强回写后第二次查同样的key,此时redis就有值了,可以直接从redis中读取default缺省值返回给业务程序,避免了把大量请求发送给mysql处理,打爆mysql------------>此种方法架不住黑客的恶意攻击,有缺陷…只能解决key相同的情况。
黑客或者恶意攻击:黑客会对你的系统进行攻击,拿一个不存在的id去查询数据,会产生大量的请求到数据库查询,可能会导致你的数据库由于压力过大而宕机。
key相同—>第一次达到mysql,空对象缓存后第二次就返回default缺省值,避免mysql再被攻击,不用再到数据库中走一圈了。
key不同—>由于存在空对象缓存和缓存回写(看自己的业务),redis中无关紧张的key也会越来越多(记得设置redis过期时间)。

方案二:Google布隆过滤器Guava解决缓存穿透
Guava中布隆过滤器的实现算是比较权威的,所以实际项目中可以直接采用Guava布隆过滤器

在这里插入图片描述

白名单过滤器实战
白名单那过滤器架构说明
误判问题:概率小还可以接受,不能从布隆过滤器中删除
全部合法的key都需要放入Guava版布隆过滤器+Redis里面,不然数据就是返回null
改POM

        <!--  Guava  Google开源的Guava中自带的布隆过滤器--><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>23.0</version></dependency>

业务类
我们的目的是再白名单里面设置100w的数据,然后再额外加入10w的数据,看一下误判率是多少

/*** @author Guanghao Wei* @create 2023-04-25 14:51*/
@Service
@Slf4j
public class GuavaWithBloomFilterService {//定义常量public static final int _1W = 10000;//定义guava布隆过滤器初始容量public static final int SIZE = 100 * _1W;//误判率,它越小,误判个数越少public static double fpp = 0.03;//创建guava布隆过滤器private BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), SIZE, fpp);public void guavaBloomFilter() {//先让bloomFilter加入100w数据for (int i = 1; i <= SIZE; i++) {bloomFilter.put(i);}//故意取10w个不在合法范围内的数据ArrayList<Object> list = new ArrayList<>(10 * _1W);//验证for (int i = SIZE + 1; i <= SIZE + (10 * _1W); i++) {if (bloomFilter.mightContain(i)) {log.info("被误判了:{}", i);list.add(i);}}log.info("误判总数量:{}", list.size());}
}
/*** @author Guanghao Wei* @create 2023-04-25 14:51*/
@Api(tags = "google工具Guava处理布隆过滤器")
@RestController
@Slf4j
public class GuavaWithBloomFilterController {@Autowiredprivate GuavaWithBloomFilterService guavaWithBloomFilterService;@ApiOperation("guava布隆过滤器插入100万样本数据并额外添加10w测试是否存在")@GetMapping("guavafilter")public void guavaBloomFilter() {guavaWithBloomFilterService.guavaBloomFilter();}
}

这里有一个误判率的知识点我们通过debug源码来学习:
在这里插入图片描述

布隆过滤器说明
在这里插入图片描述

缓存击穿
是什么
大量的请求同时查询一个key时,此时这个key正好失效了,就会导致大量的请求都打到数据库上去
简单来说就是热点key突然失效了,暴打mysql。

穿透和击穿,截然不同
热点key为什么失效?

时间到了自然清除但还未被访问到
delete掉的key,刚巧又被访问

危害
会造成某一时刻数据库请求量过大,压力剧增
一般技术部门需要知道热点key是哪些,做到心里有数防止击穿

解决
方案一:差异失效时间
对于访问频繁的热点key,干脆就不设置过期时间

方案二:互斥更新
采用双检加锁策略
案例

天猫聚划算功能实现+防止缓存击穿
在这里插入图片描述
数据类型可以选用list和zset,但这类场景一般还是选择list

实体类

/*** @author Guanghao Wei* @create 2023-04-25 15:40*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(value = "聚划算活动product信息")
public class Product {private Long id;private String name;private Integer price;private String detail;
}

service

/*** @author Guanghao Wei* @create 2023-04-25 15:42*/
@Service
@Slf4j
public class JHSTaskService {public static final String JHS_KEY = "jhs";public static final String JHS_KEY_A = "jhs:a";public static final String JHS_KEY_B = "jhs:b";@Autowiredprivate RedisTemplate redisTemplate;/*** 模拟从数据库读取20件特价商品,用于加载到聚划算的页面中** @return*/private List<Product> getProductsFromMysql() {List<Product> list = new ArrayList<>();for (int i = 1; i <= 20; i++) {Random random = new Random();int id = random.nextInt(10000);Product obj = new Product((long) id, "product" + i, i, "detail");list.add(obj);}return list;}@PostConstructpublic void init() {log.info("启动定时器天猫聚划算功能模拟开始.........O(∩_∩)O");//用线程模拟定时任务,后台任务定时将mysql里面的参加活动的商品刷进redisnew Thread(() -> {//模拟从mysql查出数据用于加载进redis,在页面展示List<Product> productList = this.getProductsFromMysql();//采用redis list数据结构的lpush命令来存储redisTemplate.delete(JHS_KEY);//加入最新的数据redisTemplate.opsForList().leftPushAll(JHS_KEY, productList);//暂停1分钟,间隔一分钟执行一次,模拟聚划算一天执行的参加活动的品牌try { TimeUnit.MINUTES.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }}, "t1").start();}
}

controller

/*** @author Guanghao Wei* @create 2023-04-25 15:42*/
@Api(tags = "聚划算页面展示控制器")
@RestController
@Slf4j
public class JHSProductController {public static final String JHS_KEY = "jhs";@Autowiredprivate RedisTemplate redisTemplate;/*** 分页查询,在高并发的情况下,只能走Redis查询,走db的话必定会吧db打垮** @param page* @param size* @return*/@ApiOperation("聚划算案例,每次1页展示5条数据")@GetMapping("product/find")public List<Product> find(int page, int size) {List<Product> list = null;long start = (page - 1) * size;long end = start + size - 1;try {list = redisTemplate.opsForList().range(JHS_KEY, start, end);if (CollectionUtils.isEmpty(list)) {//走数据库查询 TODO}log.info("参加活动的商家:{}",list);} catch (Exception e) {//出异常了,一般redis宕机了,或者redis网络抖动导致timeoutlog.error("jhs exception:{}",e);e.printStackTrace();//再次查询}return list;}}

至此步骤,上述聚划算的功能算是完成了,请思考在高并发情况下又会产生什么样的经典生产问题?
Bug和隐患说明
在这里插入图片描述

热点key突然失效导致可怕的缓存击穿:delete命令执行的一瞬间有空隙,其他请求线程找Redis为null,达到mysql,暴击mysql…
复习again
在这里插入图片描述

最终目的:2条命令原子性是其次的,主要是防止热点key突然失效暴击mysql打爆系统。
进一步升级加固案例
互斥更新—>双检加锁策略
在这里插入图片描述

差异失效时间,在本案例中给我们使用这个方式

    @PostConstructpublic void initJHSAB() {log.info("启动AB定时器天猫聚划算功能模拟开始.........O(∩_∩)O" + DateUtil.now());//用线程模拟定时任务,后台任务定时将mysql里面的参加活动的商品刷进redisnew Thread(() -> {//模拟从mysql查出数据用于加载进redis,在页面展示List<Product> productList = this.getProductsFromMysql();//先更新B缓存,且让B过期时间超过A,B做兜底redisTemplate.delete(JHS_KEY_B);redisTemplate.opsForList().leftPushAll(JHS_KEY_B, productList);redisTemplate.expire(JHS_KEY_B, 86410L, TimeUnit.SECONDS);//在更新A缓存redisTemplate.delete(JHS_KEY_A);redisTemplate.opsForList().leftPushAll(JHS_KEY_A, productList);redisTemplate.expire(JHS_KEY_A, 86400L, TimeUnit.SECONDS);//暂停1分钟,间隔一分钟执行一次,模拟聚划算一天执行的参加活动的品牌try { TimeUnit.MINUTES.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }}, "t1").start();}
    @ApiOperation("AB双缓存架构,防止热点key突然失效")@GetMapping("product/findAB")public List<Product> findAB(int page, int size) {List<Product> list = null;long start = (page - 1) * size;long end = start + size - 1;try {list = redisTemplate.opsForList().range(JHS_KEY_A, start, end);if (CollectionUtils.isEmpty(list)) {log.info("-------A缓存已经失效或者过期了,记得人工修改,B缓存继续顶着");list = redisTemplate.opsForList().range(JHS_KEY_B, start, end);if (CollectionUtils.isEmpty(list)) {//TODO 走数据库查询}}} catch (Exception e) {//出异常了,一般redis宕机了,或者redis网络抖动导致timeoutlog.error("jhs exception:{}", e);e.printStackTrace();//再次查询}return list;}

相关文章:

14、缓存预热+缓存雪崩+缓存击穿+缓存穿透

缓存预热缓存雪崩缓存击穿缓存穿透 ● 缓存预热、雪崩、穿透、击穿分别是什么&#xff1f;你遇到过那几个情况&#xff1f; ● 缓存预热你是怎么做到的&#xff1f; ● 如何避免或者减少缓存雪崩&#xff1f; ● 穿透和击穿有什么区别&#xff1f;它两一个意思还是截然不同&am…...

【PostGreSQL】PostGreSQL到Oracle的数据迁移

项目需要&#xff0c;有个数据需要导入&#xff0c;拿到手一开始以为是mysql&#xff0c;结果是个PostGreSQL的数据&#xff0c;于是装数据库&#xff0c;但这个也不懂呀&#xff0c;而且本系统用的Oracle&#xff0c;于是得解决迁移转换的问题。 总结下来两个思路。 1、Postg…...

jupyter notebook出现ERR_SSL_VERSION_OR_CIPHER_MISMATCH解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…...

前端进阶Html+css10----定位的参照对象(高频面试题)

1.relative的参照对象 1&#xff09;元素按照标准流进行排布&#xff1b; 2&#xff09;定位参照对象是元素自己原来的位置&#xff0c;可以通过left、right、top、bottom来进行位置调整&#xff1b; 2.absolute&#xff08;子绝父相&#xff09; 1&#xff09;元素脱离标准流…...

总结记录Keras开发构建神经网络模型的三种主流方式:序列模型、函数模型、子类模型

Keras是一个易于使用且功能强大的神经网络建模库&#xff0c;它是基于Python语言开发的。Keras提供了高级API&#xff0c;使得用户能够轻松地定义和训练神经网络模型&#xff0c;无论是用于分类、回归还是其他任务。 Keras的主要特点如下&#xff1a; 简单易用&#xff1a;Kera…...

python环境建设

1. 查看通过pip安装包的路径 问题&#xff1a;devchat vscode中配置需要查找devchat的安装路径&#xff0c;使用pip相关的命令查看 pip list | grep package_name 命令显示获取已安装包的信息&#xff08;包名与版本号&#xff09;pip show package_name命令能显示该安装的包…...

Python学习笔记第五十九天(Matplotlib 安装)

Python学习笔记第五十九天 Matplotlib 安装后记 Matplotlib 安装 本章节&#xff0c;我们使用 pip 工具来安装 Matplotlib 库&#xff0c;如果还未安装该工具&#xff0c;可以参考 Python pip 安装与使用。 如果您还没有安装Matplotlib&#xff0c;您可以按照以下步骤在Pytho…...

(6)(6.3) 自动任务中的相机控制

文章目录 前言 6.3.1 概述 6.3.2 自动任务类型 6.3.3 创建合成图像 前言 本文介绍 ArduPilot 的相机和云台命令&#xff0c;并说明如何在 Mission Planner 中使用这些命令来定义相机勘测任务。这些说明假定已经连接并配置了相机触发器和云台(camera trigger and gimbal ha…...

什么是cssreset ?为什么要用到cssreset?

1&#xff0c;什么是cssreset ? 顾名思义&#xff0c;css reset&#xff0c;样式重置。即重新设置界面的样式。 CSS reset&#xff0c;又叫做 CSS 重写或者 CSS 重置&#xff0c;用于改写HTML标签的默认样式。 有些HTML标签在浏览器里有默认的样式&#xff0c;例如 p 标签有上…...

SpringCloud学习笔记(四)_ZooKeeper注册中心

基于Spring Cloud实现服务的发布与调用。而在18年7月份&#xff0c;Eureka2.0宣布停更了&#xff0c;将不再进行开发&#xff0c;所以对于公司技术选型来说&#xff0c;可能会换用其他方案做注册中心。本章学习便是使用ZooKeeper作为注册中心。 本章使用的zookeeper版本是 3.6…...

【算法专题突破】双指针 - 移动零(1)

目录 写在前面 1. 题目解析 2. 算法原理 3. 代码编写 写在最后&#xff1a; 写在前面 在进行了剑指Offer和LeetCode hot100的毒打之后&#xff0c; 我决心系统地学习一些经典算法&#xff0c;增强我的综合算法能力。 1. 题目解析 题目链接&#xff1a;283. 移动零 - 力…...

Nginx高可用集群

目录 一.简介二.案例1.实现思路2.配置文件修改3.实现效果故障转移机制 一.简介 以提高应用系统的可靠性&#xff0c;尽可能地减少中断时间为目标&#xff0c;确保服务的连续性&#xff0c;达到高可用的容错效果。例如“故障切换”、“双机热备”、“多机热备”等都属于高可用集…...

Rust 基础入门 ——所有权 引言 :垃圾自动回收机制的缺陷。

在以往&#xff0c;内存安全几乎都是通过 GC 的方式实现&#xff0c;但是 GC 会引来性能、内存占用以及 Stop the world 等问题&#xff0c;在高性能场景和系统编程上是不可接受的&#xff0c; 我们先介绍一下这些概念都是什么&#xff1a; 内存安全是指程序在运行过程中不会访…...

Ubuntu20.04安装软件报错:The following packages have unmet dependencies

Ubuntu20.04更换阿里云源后安装软件都会报错&#xff1a;The following packages have unmet dependencies 查看资料&#xff0c;大概是ubuntu本身的源比较版本较老&#xff0c;而阿里云的源比较新&#xff0c;因此版本不匹配造成依赖的库不匹配&#xff0c;所以只要将阿里云的…...

Java 与设计模式(12):享元模式

一、定义 享元模式是一种结构型设计模式&#xff0c;旨在有效地共享对象以减少内存使用和提高性能。该模式的核心思想是通过共享尽可能多的相似对象来减少内存占用。它将对象分为可共享的内部状态和不可共享的外部状态。内部状态是对象的固有属性&#xff0c;可以在多个对象之…...

React配置代理(proxy)

使用axios进行请求&#xff0c;而配置代理过程。 第一种 在package.json中&#xff0c;添加proxy配置项,之后所有的请求都会指向该地址 但这种方法只能配置一次&#xff0c;也只有一个 示例&#xff1a; "proxy":"https://localhost:5000" 添加后&am…...

队列(Queue):先进先出的数据结构队列

栈与队列https://blog.csdn.net/qq_45467165/article/details/127958960?csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22127958960%22%2C%22source%22%3A%22qq_45467165%22%7D 队列&#xff08;Queue&#xff09;是一种常见的线…...

CentOS ens160 显示disconnected

使用nmcli device查看网卡状态&#xff0c;显示如图&#xff1a; 检查宿主机系统VMware DHCP Sevice和VMware NAT Sevice服务是否正常运行。 右键点击我的电脑管理按钮&#xff0c;打开计算机管理点击服务...

使用 ChatGPT 创建 PowerPoint 演示文稿

让 ChatGPT 成为您的助手来帮助您编写电子邮件很简单,因为众所周知,它非常能够生成文本。很明显,ChatGPT 无法帮助您做饭。但您可能想知道它是否可以生成文本以外的其他内容。在上一篇文章中,您了解到 ChatGPT 只能通过中间语言为您生成图形。在这篇文章中,您将了解使用中…...

matlab将数组值划分为两类

例如&#xff1a;大于0的处理为1&#xff0c;小于0的处理为-1. 当然&#xff0c;可以选择循环结构和选择结构&#xff0c;但是效率会很低。 这里直接使用逻辑语句完成。 % 不使用循环语句&#xff0c;将数组内值划分为两类 clc; clearvars; a[-0.1422 , -0.0433 , 0.1131 …...

【点击新增一个下拉框 与前一个内容一样 但不能选同一个值】

点击新增一个下拉框 与前一个内容一样 但不能选同一个值 主要是看下拉选择el-option的disabled,注意不要混淆 <el-form label-width"120px" :model"form" ref"form" style"color: #fff"><template v-for"(trapolicy, i…...

【Gitee提交pr】

Gitee提交pr 什么是pr怎样提交一个pr嘞&#xff1f; 什么是pr pr:指的是将自己的修改从自己的账号仓库dev下提交到官方账号仓库master下&#xff1b; 通俗来讲就是Gitee线上有属于自己的分支&#xff0c;然后本地在自己地分支修改完代码之后&#xff0c;提交到自己的线上分支&a…...

一款打工人必备的电脑端自律软件!!冲鸭打工人!!

你&#xff01;有没有渴望进步&#xff01;&#xff01; 你&#xff01;有没有渴望变强&#xff01;&#xff01;&#xff01; 成为大佬&#xff01;&#xff01;&#xff01;超越巨佬&#xff01;&#xff01;&#xff01; 这就是一款为这样的你量身定做的程序&#xff1a;输入…...

【Vue框架】 router和route是什么关系

前言 之前没太注意&#xff0c;写着写着突然发现它们貌似不太一样&#xff0c;记录以下&#xff0c;回顾的看总结就好。 1、总结✨ route&#xff1a;当前激活路由的对象&#xff0c;用于访问和操作当前路由的信息 router&#xff1a;管理多个route的对象&#xff0c;整个应…...

整理mongodb文档:聚合管道

个人博客 整理mongodb文档:聚合管道 个人博客&#xff0c;求关注&#xff0c;电脑版看体验更加&#xff0c;如果不够清晰&#xff0c;请指出来&#xff0c;谢谢 文章概叙 文章主要通过几个常用的聚合表达式来介绍聚合管道的使用&#xff0c;以及从索引的角度来介绍聚合管道…...

Delphi 11.3 FMX 多设备平台中使用 TGrid 实现类似 TDBGrid 的效果

Delphi Firemonkey 中 TDBGrid 这个控件已经没有了。如何实现类似这个效果呢。其实可以用TGrid 来实现。以下用 11.3 来讲解。 查询里面用到的 connection 和 query 等控件那些一般的数据库用法&#xff0c;就不做过多描述了。请参考其他资料。 方法一.通过界面配置来实现 在…...

Qt-事件循环与QtConcurrent、QThread结合使用时注意的点

QEventLoop和QtConcurrent可以结合使用达到主线程ui不阻塞同步执行的效果&#xff0c;但是要小心避坑&#xff0c;查看如下代码&#xff1a; QEventLoop loop; QtConcurrent::run([&]() {doSomething();loop.quit(); }); loop.exec();上述写法存在两个问题&#xff1a; Q…...

基于MongoDB的空间数据存储与查询

一、概念说明 1.1 空间地理数据 MongoDB 中使用 GeoJSON对象 或 坐标对 描述空间地理数据。MongoDB使用 WGS84 参考系进行地理空间数据查询。 1、MongoDB支持空间数据的存储&#xff0c;数据类型需要限制为GeoJSON; 2、MongoDB可以为GeoJSON类型数据建立索引&#xff0c;提升空…...

jquery中pdf的上传、下载及excel导出

jquery中pdf的上传、下载及excel导出 1.PDF上传 pdfUpload2. pdf下载和excel导出用的一种方法&#xff0c;并且需要引入utils.js2.1PDF下载 pdfDownload2.2导出Excel excelExport 1.PDF上传 pdfUpload //PDF上传 pdfUpload window.pdfUploadfunction (obj){layer.open({type:…...

【MyBatis】:PageHelper分页插件与特殊字符处理

目录 一、PageHelper介绍 二、PageHelper使用 1. 导入pom依赖 2. Mybatis.cfg.xml 配置拦截器 3. 配置 Mapper.xml 4. 编写测试 三、特殊字符处理 1. 使用转义字符 2. 使用CDATA 区段 一、PageHelper介绍 PageHelper 是 Mybatis 的一个插件&#xff0c;这里就不扯了&a…...

网站搜索排名优化怎么做/网络营销推广方法十种

2019独角兽企业重金招聘Python工程师标准>>> Linux mmseg 同义词/复合分词处理&#xff1a; 其基本使用状况为&#xff1a; 词库包含&#xff1a; 南京西路、南京、西路 索引时&#xff1a; 文本中的“南京西路”会被同时索引为以上三者 查询时&#xff1a; 输入南京…...

网站开发专业就业前系军/南京seo域名

处理JavaScript函数上下文时可能遇到一些问题。在回调函数中&#xff08;例如事件处理器&#xff09;&#xff0c;函数上下文与预期不符&#xff0c;但可以使用call或apply方法绕过。在本节中&#xff0c;我们看看另外两个选择&#xff1a;箭头函数和bind方法&#xff0c;在一些…...

网站建设费用明细表/关于网络营销的方法

关于Spring Web Services框架 Spring web services(以下简称&#xff1a;Spring WS)框架是springframework东家SpringSource公司旗下的一个子项目。目前的版本是1.5M1&#xff0c;最新版本可以从spirngframework网站下载,项目地址是&#xff1a;http://www.springframework.org…...

泌阳专业网站建设/西安百度公司官网

地址 http://www.jianshu.com/p/736dd7b63ece 目录 概念存储读取概念 文件存储是 Android 中最基本的一种数据存储方式&#xff0c;它不对存储的内容进行任何的格式化处理&#xff0c;所有数据都是原封不动的保存到文件当中的。它比较适合用于存储一些简单的文本数据或二进制数…...

什么网站做外贸最多的/关于营销的最新的新闻

2019独角兽企业重金招聘Python工程师标准>>> public int dogetUserIdAndFindUserTokenTimeout(String userToken) throws Exception{ //通过userToken 获取userId ,并且 检查 令牌是否过时了&#xff0c;这样就不用经过拦截器了,app 方便&#xff0c;我的架…...

用网站空间可以做有后台的网站吗/关键词优化顾问

反复读了几遍王咏武的《向依赖关系宣战——依赖倒置、控制反转和依赖注入辨析》再次感受到自己要学的东西真的很多&#xff0c;废话不多说。下面阐述几个实例&#xff1a;1比如a框架要使用b框架&#xff0c;为了隔离这两个框架&#xff0c;就要在中间引入一个mid框架。为了防止…...