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

SpringCloud学习路线(9)——服务异步通讯RabbitMQ

一、初见MQ

(一)什么是MQ?

MQ(MessageQueue),意思是消息队列,也就是事件驱动架构中的Broker。

(二)同步调用

1、概念: 同步调用是指,某一服务需要多个服务共同参与,但多个服务之间有一定的执行顺序,当每一个服务都需要等待前面一个服务完成才能继续执行。

2、存在的问题

  • 耦合度高: 新需求需要改动原代码
  • 性能下降: 调用者需要等待服务提供者相应,如果调用链过长则响应时间等于每次调用的时间之和。
  • 资源浪费: 调用链的每个服务在等待响应过程中,不会释放请求资源,高并发场景下会浪费系统资源。
  • 级联失败: 若服务提供者出现宕机,所有调用者都会因故障而导致整个服务集群故障。

(三)异步调用

1、实现模式: 异步调用常见实现的就是事件驱动模式。

2、事件驱动的优势

  • 服务解耦: 只需要将请求交付给事件管理器进行管理即可完成服务。
  • 性能提升: 与客户交互的服务短时间就能完成,并不需要等待后续服务完成。
  • 服务弱依赖: 其它服务宕机不影响服务集群的使用
  • 流量缓冲: 事件管理器通过任务队列的方式,使得订阅的服务按照自身速度进行执行。

3、事件驱动的缺点

  • 高度依赖Broker的可靠性、安全性、吞吐能力
  • 架构复杂时,业务没有明显的流程线,不便于跟踪管理

(四)MQ常见框架

RabbitMQ(中小企业)ActiveMQRocketMQ(大型企业)Kafka
公司/社区RabbitApacheAlibabaApache
开发语言ErlangJavaJavaJava
协议支持AMQP,XMPP,SMTP,STOMPOpenWire,STOMP,REST,XMPP,AMQP自定义协议自定义协议
可用性一般
单机吞吐量一般极高
消息延迟微妙级毫秒级毫秒级毫秒以内
消息可靠一般一般

二、使用MQ

(一)RabbitMQ概述

RqbbitMQ是基于Erlang语言开发的开源消息通讯中间件,官方地址:https://rabbitmq.com/

(二)安装MQ

docker pull rabbitmq:3-management

在这里插入图片描述

(三)运行RabbitMQ

#配置 MQ的用户名和密码,容器名和主机名,端口,镜像名 ,注意:15672端口是MQ的控制台访问端口,5672是对外暴露的消息通信端口
docker run -e RABBITMQ_DEFAULT_USER=xxx -e RABBITMQ_DEFAULT_PASS=xxxx --name mq --hostname mq1 -p 15672:15672 -p 5672:5672 -d rabbitmq:3-management

在这里插入图片描述

访问MQ的控制台

在这里插入图片描述
(4)RabbitMQ的整体结构

在这里插入图片描述

(5)RabbitMQ中的几个概念

  • channel: 操作MQ的工具
  • exchange: 路由消息到队列
  • queue: 缓存消息
  • Virtual Host: 虚拟主机,是对queue,exchange等资源进行逻辑分组

(6)常见的MQ模型

  • 基本消息队列(BasicQueue): Publisher —1:1— Queue —1:1— Customer
  • 工作消息队列(WorkQueue): Publisher —1:1— Queue —1:n— Customer
  • 发布/订阅(Publish、Subscribe): 根据交换机类型又有三种模型
    • Fanout Exchange: 广播,Publisher—1:1—Exchange—1:n—Queue—1:1—Customer
    • Direct Exchange: 路由,Publisher—1:1—Exchange—1:n—Queue—1:1—Customer
    • Topic Exchange: 主题,
  • RPC
  • 发布者确认

第一种:基本消息队列的基本使用

包含三种角色:publisherqueueconsumer

  • publisher: 消费发布者,将消息发布到队列queue
  • queue: 消息队列,负责接受并缓存消息
  • consumer: 订阅队列,处理队列中的消息

收发消息的过程: 获取连接 》 建立通信通道 》 创建消息队列 》 收发消息 》 释放资源

1、publisher和consumer引入依赖

  <dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId>
</dependency>

2、Publisher创建发送消息通道

@SpringBootTest
class PublisherApplicationTests {@Testvoid testSendMessage() throws IOException, TimeoutException {
//        1、建立连接ConnectionFactory connectionFactory = new ConnectionFactory();
//        2、设置连接参数connectionFactory.setHost("192.168.92.131");connectionFactory.setPort(5672);connectionFactory.setVirtualHost("/");connectionFactory.setUsername("root");connectionFactory.setPassword("root");
//        3、建立连接Connection connection = connectionFactory.newConnection();
//        4、建立通信通道ChannelChannel channel = connection.createChannel();
//        5、创建队列String queueName = "simple.queue";channel.queueDeclare(queueName,false,false,false,null);
//        6、发送信息String message = "hello,rabbitmq!";channel.basicPublish("",queueName,null,message.getBytes(StandardCharsets.UTF_8));System.out.println("发送消息成功:【"+message+"】");
//        7、关闭通道和连接channel.close();connection.close();}
}

2、Consumer创建订阅通道

class ConsumerApplicationTests {public static void main(String[] args) throws IOException, TimeoutException {//        1、建立连接ConnectionFactory connectionFactory = new ConnectionFactory();//        2、设置连接参数connectionFactory.setHost("192.168.92.131");connectionFactory.setPort(5672);connectionFactory.setVirtualHost("/");connectionFactory.setUsername("root");connectionFactory.setPassword("root");
//        3、建立连接Connection connection = connectionFactory.newConnection();
//        4、建立通信通道ChannelChannel channel = connection.createChannel();
//        5、创建队列String queueName = "simple.queue";channel.queueDeclare(queueName,false,false,false,null);
//        6、订阅消息channel.basicConsume(queueName,true,new DefaultConsumer(channel){@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//                7、处理消息String message = new String(body);System.out.println("接收到消息:【"+message+"】");}});System.out.println("等待接收消息....");}
}

第二种:Work Queue 工作队列

与基本队列的区别在于,它能使用多个订阅队列进行高效的处理请求。(因为一个订阅队列的处理速度是有限的)

使用过程与基本队列几乎一致,只是开启了多个订阅队列。

在使用过程中我们会发现,多个订阅队列对任务的分配是平均的,这就是预取机制

我们需要的是快速处理的订阅队列获取更多的请求,慢速处理的订阅队列获取少量的请求,它如何实现呢?

通过修改配置文件,设置一个 preFetch 值。

spring:rabbitmq:host: 192.168.92.131 #IPport: 5672 #端口virtual-host: / #虚拟主机username: root #用户名password: root #密码listener:simple:prefetch: 1 # 每次取 1 个请求,处理完才能取下一个。

第三种:FanoutQueue 广播消息队列

SpringAMQP提供声明交换机、队列、绑定关系的API

主要使用的是Exchange.FanoutExchange类。

实现思路:
1、在consumer服务,声明队列,交换机,并将两者绑定。

@Configuration
public class FanoutConfig{//交换机@Beanpublic FanoutExchange fanoutExchange(){return new FanoutExchange("com.fanout");}//队列@Beanpublic Queue fanoutQueue1(){return new Queue("com.queue1");}//绑定关系@Beanpublic Binding bindingQueue(Queue fanoutQueue1,FanoutExchange fanoutExchange){return BindingBuilder.bind(fanoutQueue).to(fanoutExchange);}//...以相同方式声明第2个队列,并完成绑定}

2、在consumer服务,编写两个消费者方法,分别监听fanout.queue1和fanout.queue2

@Component
public class SpringRabbitListener {@RabbitListener(queues = "com.queue1")public void listenFanoutQueue1(String msg) throws InterruptedException {//...处理结果}@RabbitListener(queues = "com.queue2")public void listenFanoutQueue2(String msg) throws InterruptedException {//...处理结果}
}

3、在publisher编写测试方法,向交换机发送信息

@Test
public void sendFanoutExchange() {//1、交换机String exchangeName = "com.fanout";//2、消息String message = "Hello Fanout";//3、发送消息rabbitTemplate.covertAndSend(exchangeName, "", message);
}

第四种:路由信息队列

路由模式的流程: 即设置密钥的绑定关系,只有携带相应的密钥才能进入相应的队列

  • 每一个 QueueExchange 设置一个 BindingKey
  • 发布者发送消息时,需要指定消息的 RoutingKey
  • Exchange根据消息路由到 BindingKeyRoutingKey 一致的队列

实现思路:
1、利用 @RabbitListener 声明Exchange、Queue、RoutingKey

@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "direct.queue1"), exchange = @Exchange(name = "com.exchange", type = ExcahngeTypes.DIRECT), key = {"red","blue"}))
public void listenRoutingQueue1(String msg) throws InterruptedException {//...处理结果
}@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "direct.queue2"), exchange = @Exchange(name = "com.exchange", type = ExcahngeTypes.DIRECT), key = {"red","green"}))
public void listenRoutingQueue2(String msg) throws InterruptedException {//...处理结果

2、发送消息实现

//指定队列处理
@Test
public void sendRoutingExchange1(){//交换机,消息String exchangeName = "com.exchange";String message = "Hello,RoutingMQ";//发送消息rabbitTemplate.covertAndSend(exchangeName, "blue", message);
}//多队列处理
@Test
public void sendRoutingExchange2(){//交换机,消息String exchangeName = "com.exchange";String message = "Hello,RoutingMQ";//发送消息rabbitTemplate.covertAndSend(exchangeName, "red", message);
}

第五种:主题信息队列(通配key)

TopicExchange 与 DirectExchange 的区别: routingkey必须是多个单词的列表,并且以,分割。并且Queue与Exchange指定的BindingKey时可使用通配符:

  • **#:**代指 0 / n 个单词
  • *: 代指一个单词

实现思路:
1、通过 @RabbitListener 声明Exchange、Queue、RoutingKey

@RabbitListener(bingdings = @QueueBinding(exchange = @Exchange(name = "com.exchange", type = ExchangeTypes.TOPIC), queue = @Queue(name = "com.queue1"), key = {"china.#"}))
public void listenTopicQueue1(String msg) {//处理代码....
}@RabbitListener(bingdings = @QueueBinding(exchange = @Exchange(name = "com.exchange", type = ExchangeTypes.TOPIC), queue = @Queue(name = "com.queue2"), key = {"#.news"}))
public void listenTopicQueue2(String msg) {//处理代码....
}

2、在publisher服务中,向交换机发送消息

@Test
public void sendTopicMessage(){//交换机,消息String exchangeName = "com.exchange";String message = "Hello,Topic";rabbitTemplate.convertAndSend(exchangeName,"china.call",message);
}

四、SpringAMQP

(一)概念

  • AMQP: Advanced Message Queuing Protocol 传递消息队列协议,是用于在应用程序或之间传递业务消息的开放标准。该协议与语言及平台无关,更符合为服务中独立性的要求。
  • Spring AMQP: Spring AMQP是基于AMQP协议定义的一套API规范,提供了模板来发送和接收消息。其中 spring-amqp是基础抽象,spring-rabbit是底层的默认实现。

(二)实现基础消息队列

1、引入spring-amqp依赖

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency>

2、publisher服务中利用RabbitTemplate发送消息到任务队列

  • 配置mq连接信息
spring:rabbitmq:host: 192.168.92.131 #IPport: 5672virtual-host: /username: rootpassword: root
  • 编写发送方法
	@Autowiredprivate RabbitTemplate rabbitTemplate;@Testpublic void sendMessage(){String queueName = "simple.queue";String message = "Hello World";rabbitTemplate.convertAndSend(queueName,message);}

3、在consumer服务中编写消费逻辑,绑定simple.queue队列

  • 配置mq连接信息
spring:rabbitmq:host: 192.168.92.131 #IPport: 5672virtual-host: /username: rootpassword: root
  • 编写发送方法1
	@Autowiredprivate RabbitTemplate rabbitTemplate;@Testpublic void getMessage(){String queueName = "simple.queue";// receive 表示接收方法,接收到的信息会封装到Message,可以看receive的返回值Message message = rabbitTemplate.receive(queueName);// Message.getBody 是 byte[]System.out.println(new String(message.getBody()));}
  • 编写发送方法2
    • 创建一个监听类
// 注册成 Bean 对象
@Component
public class SpringRabbitListener {// 监听器注释,queues = 订阅队列,并将返回值注入参数列表中	@RabbitListener(queues = "simple.queue")public void ListenSimpleQueueMessage(String msg){System.out.println("Spring 消费者接收到消息:【" + msg + "】");}
}

(三)消息转换器

为了让我们能够自由识别consumer发送的消息,则需要使用的是消息转换器

消息转换器如何使用?

Spring对消息对象的处理是由org.springframework.amqp.support.converter.MessageConverter来处理,默认实现的是SimpleMessageConverter,基于ObjectObjectOutputStream完成序列化。

我们只需要定义一个 MessageConverter 类型的Bean即可,推荐使用JSON序列化

1、publisher引入依赖


<!-- 接收消息需要使用jackson的转换依赖 -->
<dependency><groupId>com.fasterxml.jackson.dataformat</groupId><artifactId>jackson-dataformat-xml</artifactId><version>2.9.10</version>
</dependency><!-- 发送消息需要使用jackson的核心依赖 -->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId>
</dependency>

2、publisher启动类,声明MessageConverter

@Bean
public MessageConverter jsonMessageConverter(){return new Jackson2JsonMessageConverter();
}

3、consumer启动类,声明MessageConverter

@Bean
public MessageConverter jsonMessageConverter(){return new Jackson2JsonMessageConverter();
}

4、监听队列消息

@RabbitListener(queues = "object.queue")
public void listenObjectMessage(Object msg) {//处理数据....
}

相关文章:

SpringCloud学习路线(9)——服务异步通讯RabbitMQ

一、初见MQ &#xff08;一&#xff09;什么是MQ&#xff1f; MQ&#xff08;MessageQueue&#xff09;&#xff0c;意思是消息队列&#xff0c;也就是事件驱动架构中的Broker。 &#xff08;二&#xff09;同步调用 1、概念&#xff1a; 同步调用是指&#xff0c;某一服务…...

postcss-pxtorem适配插件动态配置rootValue(根据文件路径名称,动态改变vue.config里配置的值)

项目背景&#xff1a;一个项目里有两个分辨率的设计稿(1920和2400)&#xff0c;不能拆开来打包 参考&#xff1a; 是参考vant插件&#xff1a;移动端Vant组件库rem适配下大小异常的解决方案&#xff1a;https://github.com/youzan/vant/issues/1181 说明&#xff1a; 因为vue.c…...

代码随想录算法训练营第二十三天 | 额外题目系列

额外题目 1365. 有多少小于当前数字的数字借着本题&#xff0c;学习一下各种排序未看解答自己编写的青春版重点代码随想录的代码我的代码(当天晚上理解后自己编写) 941.有效的山脉数组未看解答自己编写的青春版重点代码随想录的代码我的代码(当天晚上理解后自己编写) 1207. 独一…...

UiAutomator

运行Espresso和UI Automator测试时要使用模拟器。国内手机的ROM大多进行过修改&#xff0c;可能加入很多限制&#xff0c;导致测试无法正常运行。 Espresso只支持一个活动内部交互行为的测试。跨越多个活动、多个应用的场景需要使用UI Automator。使用Espresso和UI Automator的…...

stm32标准库开发常用函数的使用和代码说明

文章目录 GPIO&#xff08;General Purpose Input/Output&#xff09;NVIC&#xff08;Nested Vectored Interrupt Controller&#xff09;DMA&#xff08;Direct Memory Access&#xff09;USART&#xff08;Universal Synchronous/Asynchronous Receiver/Transmitter&#xf…...

有关合泰BA45F5260中断的思考

最近看前辈写的代码&#xff0c;发现这样一段代码&#xff1a; #ifdef SUPPORT_RF_NET_FUNCTION if(UART_INT_is_L()) { TmrInsertTimer(eTmrHdlUartRxDelay,TMR_PERIOD(2000),NULL); break; } #endif 其中UART_INT_is_L&am…...

Numpy-算数函数与数学函数

⛳算数函数 如果参与运算的两个对象都是ndarray&#xff0c;并且形状相同&#xff0c;那么会对位彼此之间进 第 30 页 行&#xff08; - * /&#xff09;运算。NumPy 算术函数包含简单的加减乘除: add()&#xff0c;subtract()&#xff0c;multiply() 和divide()。 &#x1f…...

Nginx在springboot中起到的作用

面试时这样回答&#xff1a; 在Spring Boot项目中使用Nginx可以有以下用途&#xff1a; 1. 反向代理&#xff1a;Nginx可以作为反向代理服务器&#xff0c;将外部请求转发到后端的Spring Boot应用&#xff0c;并可以实现负载均衡、高可用、缓存等功能&#xff0c;提高系统的性…...

12.(开发工具篇vscode+git)vscode 不能识别npm命令

1&#xff1a;vscode 不能识别npm命令 问题描述&#xff1a; 解决方式&#xff1a; &#xff08;1&#xff09;右击VSCode图标&#xff0c;选择以管理员身份运行&#xff1b; &#xff08;2&#xff09;在终端中执行get-ExecutionPolicy&#xff0c;显示Restricted&#xff…...

如何在MacBook上彻底删除mysql

好久以前安装过&#xff0c;但是现在配置mysql一直出错&#xff0c;索性全部删掉重新配置。 一、停止MySQL服务 首先&#xff0c;请确保 MySQL 服务器已经停止运行&#xff0c;以免影响后续的删除操作。 sudo /usr/local/mysql/support-files/mysql.server stop如果你输入之…...

web攻击面试|网络渗透面试(一)

Web攻击面试大纲 常见Web攻击类型 1.1 SQL注入攻击 1.2 XSS攻击 1.3 CSRF攻击 1.4 命令注入攻击SQL注入攻击 2.1 基本概念 2.2 攻击原理 2.3 防御措施XSS攻击 3.1 基本概念 3.2 攻击原理 3.3 防御措施CSRF攻击 4.1 基本概念 4.2 攻击原理 4.3 防御措施命令注入攻击 5.1 基本概…...

VBA操作WORD(六)另存为不含宏的文档

Sub 另存为不含宏的文档()Application.DisplayAlerts False Application.ScreenUpdating FalseDim oDoc As DocumentSet oDoc Word.ActiveDocumentDim oRng As RangeSet oRng oDoc.ContentDim sPath As String默认存储路径&#xff0c;当前用户桌面&#xff0c;注释掉的是当…...

分享69个Java源码,总有一款适合您

Java源码 分享69个Java源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c;大家下载后可以看到。 源码下载链接&#xff1a; https://pan.baidu.com/s/1ZgbJhMNwIyFyqFzHsDdL5w 提取码&a…...

《cool! autodistill帮你标注数据训练yolov8模型》学习笔记

《cool! autodistill帮你标注数据训练yolov8模型》 Summary Autodistill是一个用于自动标注数据训练边缘模型的工具。 Highlights &#x1f4a1; Autodistill由Robotflow推出&#xff0c;用于训练建立部署计算机视觉模型。&#x1f4bb; 通过使用大模型自动标注和训练小模型…...

Rust vs Go:常用语法对比(十)

题图来自 Rust vs. Golang: Which One is Better?[1] 182. Quine program Output the source of the program. 输出程序的源代码 package mainimport "fmt"func main() { fmt.Printf("%s%c%s%c\n", s, 0x60, s, 0x60)}var s package mainimport "fm…...

SliverPersistentHeader组件 实现Flutter吸顶效果

效果&#xff1a; 20230723-212152-73_Trim 代码&#xff1a; import package:flutter/cupertino.dart; import package:flutter/material.dart;class StickHeaderPage extends StatefulWidget {overrideState<StatefulWidget> createState() {// TODO: implement creat…...

Nginx性能优化配置

一、全局优化 # 工作进程数 worker_processes auto; # 建议 CPU核心数|CPU线程数# 最大支持的连接(open-file)数量&#xff1b;最大值受限于 Linux open files (ulimit -n) # 建议公式&#xff1a;worker_rlimit_nofile > worker_processes * worker_connections…...

杭州多校2023“钉耙编程”中国大学生算法设计超级联赛(4)

1003Simple Set Problem 首先将元素的值 x 以及所属集合的编号 y 作为二元组 (x,y) 存入数组&#xff0c;然后按照 x 升序排列&#xff0c; 之后使用双指针扫描数组&#xff08;尺取法&#xff09;&#xff0c;当区间内出现了所有编号时更新答案的最小值&#xff0c; #includ…...

音视频入门之音频采集、编码、播放

作者&#xff1a;花海blog 今天我们学习音频的采集、编码、生成文件、转码等操作&#xff0c;我们生成三种格式的文件格式&#xff0c;pcm、wav、aac 三种格式&#xff0c;并且我们用 AudioStack 来播放音频&#xff0c;最后我们播放这个音频。 使用 AudioRecord 实现录音生成…...

在 Linux 系统中,如何发起POST/GET请求

在 Linux 系统中&#xff0c;可以使用命令行工具 curl 或者 wget 来发送 POST 请求。这两个工具都是非常常用的命令行工具&#xff0c;可以通过命令行直接发送 HTTP 请求。 1. 使用 curl 发送 POST 请求&#xff1a; curl -X POST -H "Content-Type: application/json&q…...

【Go】3、Go语言进阶与依赖管理

前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课&#xff0c;做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程&#xff0c;它的核心机制是 Goroutine 协程、Channel 通道&#xff0c;并基于CSP&#xff08;Communicating Sequential Processes&#xff0…...

【单片机期末】单片机系统设计

主要内容&#xff1a;系统状态机&#xff0c;系统时基&#xff0c;系统需求分析&#xff0c;系统构建&#xff0c;系统状态流图 一、题目要求 二、绘制系统状态流图 题目&#xff1a;根据上述描述绘制系统状态流图&#xff0c;注明状态转移条件及方向。 三、利用定时器产生时…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

回溯算法学习

一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...

【 java 虚拟机知识 第一篇 】

目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...

MyBatis中关于缓存的理解

MyBatis缓存 MyBatis系统当中默认定义两级缓存&#xff1a;一级缓存、二级缓存 默认情况下&#xff0c;只有一级缓存开启&#xff08;sqlSession级别的缓存&#xff09;二级缓存需要手动开启配置&#xff0c;需要局域namespace级别的缓存 一级缓存&#xff08;本地缓存&#…...