RabbitMQ入门
目录
MQ 相关概念
什么是MQ
MQ 的作用
什么是RabbitMQ
RabbitMQ的安装
安装 erlang
安装 RabbitMQ
安装 RabbitMQ 管理界面
开放云服务器端口
访问 RabbitMQ 管理界面
RabbitMQ 的用户角色
RabbitMQ的工作流程
Producer 和 Consumer
Connection 和 Channel
Virrtual host
Queue
Exchange
AMQP
管理界面操作
添加用户
设置虚拟机操作权限
更新或删除用户
退出当前用户
创建虚拟主机
入门代码
引入依赖
生产者代码实现
创建连接
创建 Channel
声明队列
发送消息
释放资源
消费者代码实现
消费消息
完整代码
生产者代码
消费者代码
常见问题
IP、端口号不正确或未开放端口号
账号或密码错误
用户对虚拟机没有操作权限
队列不存在
资源释放的顺序
MQ 相关概念
什么是MQ
MQ(Message Queue),即 消息队列,因此,它本质上也是一个队列,遵循先进先出(FIFO),队列中存放的内容是 消息(message),消息可以非常简单,如字符串,也可以比较复杂,如内嵌对象
MQ常用于在分布式系统中传递数据,允许不同的应用程序或服务之间进行异步通信
系统之间的调用方式通常有两种:
1. 同步通信
直接调用对方的服务,数据从一端发出后可以立即到达另一端
2. 异步通信
数据从一端出发,先进入到容器中进行临时存储,触发某个条件后,再从容器中发送到另一端。而容器的一个具体实现就是 MQ
因此,MQ的主要工作就是接收并转发消息
MQ 的作用
(1)解耦系统
通过消息队列,生产者和消费者可以不直接联系。生产者发送消息到队列,消费者从队列中读取消息并进行处理。这样,生产者不需要等待消费者处理完毕,就可以继续生产消息。这样各个系统或服务之间通过消息传递数据,而不需要知道对方的实现细节,减少了组件之间的直接依赖
(2)流量控制
通过消息队列,可以暂时缓解系统负载的压力。当系统接收到大量的请求时,生产者可以将请求放入队列中,消费者逐步从队列中处理这些请求,避免瞬间高并发对系统造成的压力
(3)负载均衡
多个消费者可以从同一个队列中获取消息进行处理,从而实现负载均衡。消息队列将消息均匀地分配给多个消费者,提高系统的处理能力和效率
(4)消息分发
当多个系统需要对统一数据做出响应时,可以使用MQ进行消息分发
(5)延迟通知
消息队列可以在特定时间后再处理某些任务,比如定时任务调度、预约任务等
......
而 RabbitMQ 则是 MQ 的一种实现
什么是RabbitMQ
RabbitMQ 是一个开源的消息中间件(Message Broker),实现了消息队列的功能,允许不同的应用程序或服务之间通过消息进行异步通信。RabbitMQ 采用 Erlang 语言实现了 AMQP(Advanced Message Queuing Protocol,高级消息队列协议)标准,提供了可靠的消息传递、队列管理、消息路由等功能
RabbitMQ的安装
此处使用的是 ubuntu 来进行 RabbitMQ 的安装
RabbitMQ 包含在标准的 Ununtu 仓库中,但其包含的版本通常比最新的 RabbitMQ 发行版落后很多,因此,RabbitMQ 团队制作了软件包,可参考官网:Installing on Debian and Ubuntu | RabbitMQ
由于这种方式比较复杂,在这里就使用 Ubuntu 仓库中的版本进行安装
我们先更新软件包:
apt-get update
安装 erlang
RabbitMQ 需要 Erlang 语言的支持,因此在安装 RabbitMQ 之前需要安装erlang:
apt-get install erlang
安装完成后,可以通过 erl 命令查看 erlang 版本:
可以使用 halt(). 命令或 ctrl + c 退出:
接下来,我们继续安装 RabbitMQ
安装 RabbitMQ
apt-get install rabbitmq-server
确认是否安装成功:
systemctl status rabbitmq-server
接下来,我们继续安装 RabbitMQ 管理界面
安装 RabbitMQ 管理界面
rabbitmq-plugins enable rabbitmq_management
安装完成
接下来,就可以启动服务了(若服务已经启动,则不再需要):
service rabbitmq-server start
接下来,我们就可以访问 RabbitMQ 的管理界面了
若是使用的是云服务器,则需要先开放端口 15672
开放云服务器端口
找到防火墙或是安全组,点击添加规则:
成功开放 15672 端口
访问 RabbitMQ 管理界面
然后就可以通过 IP:port (如:http://49.232.238.62:15672/)访问界面了:
其默认的用户名和密码都为 guest
但是却提示:用户只能通过 localhost 登录
这是因为 RabbitMQ 从 3.3.0 开始禁止使用 guest 权限通过除了 localhost 外的访问
那该如何登录呢?
可以添加管理员用户,然后以管理员用户的账号进行登录
添加用户:
rabbitmqctl add_user 账号 密码
添加用户 admin,密码 123456
rabbitmqctl add_user admin 123456
添加成功
接下来,我们为用户添加权限:
rabbitmqctl set_user_tags 账号 角色名称
为 admin 添加超级管理员角色:
rabbitmqctl set_user_tags admin administrator
添加成功
接下来,我们就来了解 RabbitMQ 的用户角色
RabbitMQ 的用户角色
RabbitMQ 的用户角色分为:Administrator、Monitoring、Policymaker、Management、Impersonator 和 None
(1)Administrator(管理员)
管理员角色拥有完全的权限,可以登录管理控制台,进行系统配置、管理用户、管理虚拟主机、队列、交换机、绑定等,具有最高权限
(2)Monitoring(监控)
监控角色只拥有读取权限,可以登录管理控制台,主要用于查看 RabbitMQ 的状态和监控数据
(3)Policymaker(策略制定者)
策略制定者角色主要负责管理 RabbitMQ 的策略配置,可以登录管理控制台,比如定义如何在虚拟主机中应用策略
(4)Management(管理)
管理角色通常具有在管理 UI(Web 界面)中进行操作的权限,仅可登录管理控制台,允许用户管理系统资源
(5)Impersonator(角色代理人)
代理人角色允许一个用户模拟或“冒充”另一个用户执行操作,无法登录管理控制台,用于调试或特殊的操作场景,如运维人员需要模拟其他用户的行为来进行故障排除或审计
(6)None(无权限)
无权限角色(其他用户)表示用户没有任何特殊权限,不被授权访问任何资源,无法登录管理控制台
使用设置的用户名和密码(admin 123456)进行登录:
登录成功:
接下来,我们先来学习 RabbitMQ 的工作流程
RabbitMQ的工作流程
RabbitMQ 是一个消息中间件,也是一个生产者消费者模型,负责接收、存储并转发消息
要理解图中的流程,我们需要先来了解一些基本的概念
Producer 和 Consumer
Producer:生产者,是 RabbitMQ 的 客户端,向 RabbitMQ 发送消息
Consumer:消费者,是 RabbitMQ 的 客户端,从 RabbitMQ 接收消息
Broker:就是 RabbitMQ Server,主要用于接收和发送消息
生产者(Producer)创建消息,并将消息发送到 RabbitMQ 中(消息通常是一个带有一定业务逻辑的数据,如 JSON 字符串)消息可以带有一定的标签,RabbitMQ 会根据标签进行路由,将消息发送给符合条件的消费者(Consumer)
消费者(Consumer)连接到 RabbitMQ 服务器就可以消费消息了,在消费的过程中,标签会被丢掉,消费者只会接收到消息,并不会知道消息的生产者是谁
对于 RabbitMQ 而言,一个 RabbitMQ Broker 可以简单看做一个 RabbitMQ 服务节点,或是 RabbitMQ 服务实例,也可以将一个 RabbitMQ Broker 看做一台 RabbitMQ 服务器
Connection 和 Channel
Connection:是客户端与 RabbitMQ 服务器之间的网络连接,通常是通过 TCP 协议建立的。在 RabbitMQ 中,连接是用于承载所有消息通道的基础设施,负责传输客户端和服务器之间的所有数据和控制信息
Channel:是在一个 Connection 上进行消息传递的 "虚拟通道",一个 Connection 上可以创建多个 Channel,每个 Channel 都是独立的虚拟连接,消息的发送和接收都是基于 Channel 的。通道在 RabbitMQ 中是轻量级的资源,相比 Connection,它的创建和销毁开销较小
Virrtual host
Virtual Host(虚拟主机):在 RabbitMQ 中,Virtual Host 是一种用于隔离不同应用程序之间消息传递的机制。它允许在同一 RabbitMQ 服务器实例中创建多个逻辑上的隔离空间,每个虚拟主机可以有独立的队列、交换机、绑定、权限等设置
类似于 MySQL 中的 database,一个 MySQL 服务器可以有多个 database
Queue
Queue(队列):是 RabbitMQ 的内部对象,用于存储消息
多个消费者可以订阅同一个队列
Exchange
Exchange(交换机) :负责接收生产者发送的消息,并根据特定的规则将这些消息路由到一个或多个 Queue 中
交换机是消息路由的中心,会根据类型和规则来确定如何转发接收到的消息
我们通过一个例子来进一步理解:
寄件人(生产者)的包裹(消息)被送到到物流中心(交换机)后,物流中心(交换机)会根据收件人(消费者)的地址(一定的规则)将快递分发到不同的站点(队列),然后再送到收件人(消费者)手中
其中,进行分发的过程,就是交换机根据类型和规则来将消息转发到队列的过程
此时,我们再来看流程图:
Producer 生产了一条消息
Producer 需要连接到 RabbitMQ Broker,建立一个连接(Connection),开启一个信道(Channel)
接着,Producer 需要声明一个交换机(Exchange),用于将要发送的消息路由到指定的队列中
Producer 还需要声明一个队列(Queue),用于存放消息
次数,Producer 就可以将消息发送到 RabbitMQ Broker 中了
RabbitMQ Broker 接收消息,并存入对应的队列(Queue)中,若未找到对应队列,则根据生产者的配置,选择丢弃或是退回给生产者
我们还是以送快递为例,进一步进行理解:
RabbitMQ 可以看做物流公司,而 Broker 就像是物流公司的总部,负责协调和管理所有的物流站点,确保快递的安全,高效地运送快递
Virtual host 像是物流公司为不同的客户划分的独立运输中心,每个运输中心都有自己的仓库(Queue),分拣规则(Exchange)和运输路线(Connection 和 Channel),确保不同客户的包裹处理互不干扰,同时可以提供定制化的服务
Queue 就类似于快递站的一个个仓库,用来存放等待派送的包裹,每个仓库都有一个或多个快递员(消费者)负责从仓库中取出包裹并将其派送
Connection 就像是快递员与快递站之间的通信线路,快递员需要通过这个线路来接收和派送快递(消息)
Channel 就像是快递员在运送包裹时的多个并行线路,这样,快递员就可以同时处理多个包裹,如一边派送包裹,一边接收新的包裹
接下来,我们来继续学习 AMQP
AMQP
AMQP (Advanced Message Queuing Protocol) 是一种开放标准的消息传递协议,旨在支持不同平台和编程语言之间的消息通信。AMQP定义了一套确定消息交换的功能,包括交换机(Exchange)、队列(Queue)等。这些组件共同工作,使得生产者能够将消息发送到交换机,然后由队列接收并等待消费者接收。AMQP还定义了一个网络协议,允许客户端应用通过该协议与消息代理和 AMQP 模型进行通信
而 RabbitMQ 是遵从 AMQP 协议的,也就是说,RabbitMQ 是 AMQP 的 Erlang 的实现,且RabbitMQ 还支持 STOWP2、MQTT2 等协议
因此,AMQP 的模型结构与 RabbitMQ 的模型结构是一样的
在了解了基本概念之后,我们来学习如何 RabbitMQ 的管理界面上的相关操作
管理界面操作
我们首先来看 admin,也就是与用户相关的操作
添加用户
进行添加用户操作:
添加成功:
点击要操作的用户,查看用户详情:
在用户详情页面,可以进行更新、删除等操作
设置虚拟机操作权限
上述我们添加用户 zhangsan 后,不能操作任何虚拟机
我们可以在用户详情页面对其进行设置:
设置成功
更新或删除用户
在详情页,还可以进行用户的更新(更新密码或权限)和删除操作
退出当前用户
在右上角,可以退出当前用户(log out)
创建虚拟主机
在 admin 页面中,点击右侧的 Virtual Hosts:
添加虚拟主机:
添加成功:
且此时登录的用户默认可以操作该虚拟主机
若需要对虚拟主机进行设置,可以点击需要设置的虚拟主机,进入详情页
添加 zhangsan 用户
添加成功:
在这里我们先简单学习用户和虚拟机相关的操作,而关于 连接、交换机、队列等操作,我们在后续学习中慢慢进行理解
在学习了上述基础后,我们就来尝试编写代码
入门代码
要编写代码,首先要分析清楚我们要实现的功能:
生产者生产消息,将消息发送给 RabbitMQ,RabbitMQ 将消息发送给消费者
因此,实现的步骤为:
(1)引入依赖
(2)编写生产者代码
(3)编写消费者代码
引入依赖
<!-- https://mvnrepository.com/artifact/com.rabbitmq/amqp-client --><dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId><version>5.20.0</version></dependency>
生产者代码实现
生产者要向 RabbitMQ 发送消息,首先需要与 RabbitMQ 建立连接
创建连接
而建立连接需要的信息有:
(1)IP
(2)端口号
(3)账号
(4)密码
(5)需要使用的虚拟主机
RabbitMQ 默认用于与客户端连接的 TCP 端口号是 5672,因此,需要提前进行开放:
为了方便演示,我们直接在 main 方法中编写代码:
public class Producer {public static void main(String[] args) throws IOException, TimeoutException {// 1. 创建连接工厂ConnectionFactory factory = new ConnectionFactory();// 2. 设置参数factory.setHost("49.232.238.62"); // ip 的默认值为 localhostfactory.setPort(5672); // 默认值为 5672factory.setVirtualHost("test01"); // 虚拟主机,默认值为 /// 账号factory.setUsername("admin"); // 用户名,默认为 guestfactory.setPassword("123456"); // 密码,默认为 guest// 3. 创建连接 ConnectionConnection connection = factory.newConnection(); // 需要处理异常,在此处直接进行抛出}
}
连接建立好后,我们接着来创建 Channel
创建 Channel
// 4. 创建 ChannelChannel channel = connection.createChannel();
声明队列
需要使用 queueDeclare 方法来声明队列
Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments) throws IOException;
我们来看这个方法中的参数和返回值:
参数:
queue:队列的名称
durable:队列是否持久化,若设置为 true,则持久化的队列会存盘,服务器重启后,消息不会丢失
exclusive:是否独占,若设置为 true,则只有一个消费者能监听队列
autoDelete:是否自动删除,当没有消费者(Consumer)时,是否自动删除队列
arguments:用于设置队列的属性
返回值:
Queue.DeclareOk:声明确认方法,用于标识队列已成功声明
声明一个名为 simple.test 的持久化队列:
// 5. 声明队列channel.queueDeclare("simple.test", true, false, false, null);
simple.test 队列不被一个消费者独占,不会自动删除,队列的属性不进行设置
声明队列后,若不存在 simple.test 队列,则会自动创建;若存在,则不进行创建,使用已有的
接下来,我们就可以向 RabbitMQ 发送消息了
发送消息
在前面我们了解到,生产者发送的消息,由 Exchange(交换机)接收,并根据特定的规则将这些消息路由到一个或多个 Queue 中
当一个新的 RabbitMQ 节点启动时,会预声明(declare)几个内置的交换机,内置交换机名称是空字符串(""),生产者发送的消息会根据队列名称直接路由到对应的队列
例如,有一个名为 "simple.test" 的队列,当我们使用内置的交换机时,可以看做生产者直接发送消息到 "simple.test" 队列中,消费者可以直接从 "simple.test" 队列中接收消息,而不需要关心交换机的存在。这种模式适合非常简单的应用场景,生产者和消费者之间的通信是一对一的
在这里,我们就使用内置的交换机来将生产者的消息存储到 "simple.test" 队列中
通过 basicPublish 方法来进行发送
我们来看 basicPublish 方法:
void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) throws IOException;
exchange:交换机名称,若使用内置的交换机,默认为 ""
routingKey:路由键,当使用内置交换机时,routingKey 为队列名称
props:配置相关信息
body:要发送的消息
// 6. 通过 channel 发送消息到队列中String message = "test...";channel.basicPublish("", "simple.test", null, message.getBytes());System.out.println("消息:" + message + " 发送成功");
释放资源
当我们发送完消息后,不要忘记释放资源
// 7. 释放资源channel.close();connection.close();
当 Connection 关闭时,Channel 也会自动关闭,因此,Channel 可以不用关闭,但是显示关闭 Channel 是一个良好的习惯
生产者的代码编写完成后,我们就可以运行代码,并观察结果了
我们先打开 RabbitMQ 管理界面 中的 Queues and Streams 界面:
运行代码,再次观察:
此时,创建了 simple.test 队列,且队列中有一条消息
我们查看 simple.test 的详细信息:
点击 Get messages:
点击 Get Message(s) 获取队列中的一条消息,可以看到, 生产者的消息成功发送到 simple.test 队列中
此时,我们注释掉释放资源的代码,再次运行程序:
就可以在 Connections 和 Channels 中查看到相关信息了:
接下来,我们继续编写消费者的代码
消费者代码实现
消费者要从 RabbitMQ 中获取消息,也需要先与其建立连接,并创建 Channel,同时声明队列 Queue
public class Consumer {public static void main(String[] args) throws IOException, TimeoutException {// 1. 创建连接工厂ConnectionFactory factory = new ConnectionFactory();// 2. 设置参数factory.setHost("49.232.238.62"); // ip 的默认值为 localhostfactory.setPort(5672); // 默认值为 5672factory.setVirtualHost("test01"); // 虚拟主机,默认值为 /// 账号factory.setUsername("admin"); // 用户名,默认为 guestfactory.setPassword("123456"); // 密码,默认为 guest// 3. 创建连接 ConnectionConnection connection = factory.newConnection(); // 需要处理异常,在此处直接抛出,并不进行处理// 4. 创建 ChannelChannel channel = connection.createChannel();// 5. 声明队列channel.queueDeclare("simple.test", true, false, false, null);}
}
也可以不声明队列,但是若队列不存在,就会抛出异常,因此,我们在编写消费者代码时也声明队列 simple.test
接下来,我们就可以消费队列中的消息了
消费消息
使用 basicConsume 方法来消费消息:
String basicConsume(String queue, boolean autoAck, Consumer callback) throws IOException;
queue:队列名称
autoAck:是否自动确认,消费者收到消息后,自动向 MQ 确认已经收到消息
callback:回调对象
我们重点来看 callback 这个回调对象,其类型为 Consumer:
Consumer 是一个接口,用于定义消息消费者的行为,当我们需要从 RabbitMQ 接收消息时,需要提供一个实现了 Consumer 接口的对象
而 DefaultConsumer 是 RabbitMQ 提供的一个默认消费者,实现类 Consumer 接口
其中,handleDelivery 方法是其核心方法
当从队列中接收到消息后,会自动调用该方法,在方法中,我们可以实现如何处理接收到的消息,如打印消息内容、将消息存储到数据库等
其中的参数有:
consumerTag:消费者标签,通常是消费者的订阅队列时指定
envelope:包含消息的封包信息,如队列名称、交换机名称等
properties:配置信息
body:消息内容
我们定义 DefaultConsumer 对象,并重写 handleDelivery 方法,在方法中实现消息的处理逻辑:
// 6. 消费消息DefaultConsumer consumer = new DefaultConsumer(channel) {// 回调方法,当接收到消息后,自动执行该方法@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {System.out.println("成功接收到消息: " + new String(body));}};
在这里,我们就简单的打印接收到的消息
再使用 basicConsume 方法消费消息:
channel.basicConsume("simple.test", true, consumer);
消费 simple.test 队列中的消息,当消费者接收到消息后,自动向 RabbitMQ 进行确认
最后,释放资源:
// 7. 释放资源channel.close();connection.close();
消费者相当于是一个监听程序,需要监听队列中是否有消息需要消费,因此,在大多数情况下,不需要关闭资源
我们运行消费者代码,并观察结果:
由于刚才生产者代码运行了两次,因此向队列中发送了两条消息,而这两条消息都成功被消费者接收
若我们不释放消费者的资源,则可以看到响应的 Connection 和 Channel
在 Queues and Streams 页面,点击右侧的 +/-:
点击添加消费者数量:
可以看到此时 simple.test 队列有一个消费者:
完整代码
以下是生产者和消费者的完整代码:
生产者代码
public class Producer {public static void main(String[] args) throws IOException, TimeoutException {// 1. 创建连接工厂ConnectionFactory factory = new ConnectionFactory();// 2. 设置参数factory.setHost("49.232.238.62"); // ip 的默认值为 localhostfactory.setPort(5672); // 默认值为 5672factory.setVirtualHost("test01"); // 虚拟主机,默认值为 /// 账号factory.setUsername("admin"); // 用户名,默认为 guestfactory.setPassword("123456"); // 密码,默认为 guest// 3. 创建连接 ConnectionConnection connection = factory.newConnection(); // 需要处理异常,在此处直接抛出,并不进行处理// 4. 创建 ChannelChannel channel = connection.createChannel();// 5. 声明队列channel.queueDeclare("simple.test", true, false, false, null);// 6. 通过 channel 发送消息到队列中String message = "test...";channel.basicPublish("", "simple.test", null, message.getBytes());System.out.println("消息:" + message + " 发送成功");// 7. 释放资源channel.close();connection.close();}
}
消费者代码
public class Consumer {public static void main(String[] args) throws IOException, TimeoutException {// 1. 创建连接工厂ConnectionFactory factory = new ConnectionFactory();// 2. 设置参数factory.setHost("49.232.238.62"); // ip 的默认值为 localhostfactory.setPort(5672); // 默认值为 5672factory.setVirtualHost("test01"); // 虚拟主机,默认值为 /// 账号factory.setUsername("admin"); // 用户名,默认为 guestfactory.setPassword("123456"); // 密码,默认为 guest// 3. 创建连接 ConnectionConnection connection = factory.newConnection(); // 需要处理异常,在此处直接抛出,并不进行处理// 4. 创建 ChannelChannel channel = connection.createChannel();// 5. 声明队列channel.queueDeclare("simple.test", true, false, false, null);// 6. 消费消息DefaultConsumer consumer = new DefaultConsumer(channel) {// 回调方法,当接收到消息后,自动执行该方法@Overridepublic void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {System.out.println("成功接收到消息: " + new String(body));}};channel.basicConsume("simple.test", true, consumer);// 7. 释放资源channel.close();connection.close();}
}
常见问题
IP、端口号不正确或未开放端口号
若连接的 IP 或是端口号不正确,又或是未开放端口号,则会连接不上,等待一段时间,程序就会抛出异常:
连接超时,没有进一步的信息
此时,就需要检查 IP 和 端口号是否正确,以及端口号是否已经开放
账号或密码错误
当账号或密码错误时,会抛出异常:
此时就需要检查用户名和密码是否正确
用户对虚拟机没有操作权限
进入 admin 详情页,删除 admin 对 test01 虚拟主机的操作权限:
此时再次进行访问:
当前用户对 test01 虚拟主机没有操作权限
此时我们就需要检查当前用户的操作权限
队列不存在
找到 simple.test 队列,进入详情页:
将其删除:
并注释掉队列声明的代码,此时再次运行程序:
在虚拟主机 test01 上不存在 simple.test 队列
因此,我们最好每次都将声明队列加上,防止队列不存在时抛出异常,影响后续程序的执行
资源释放的顺序
在关闭资源时,一定是先关闭 Channel,再关闭 Connectiion
若先关闭 Connection,再关闭 Channel,就会出现问题:
这是因为当 Connection 关闭时,Channel 也会自动关闭,而此时再尝试关闭 Channel,自然会报错
相关文章:
RabbitMQ入门
目录 MQ 相关概念 什么是MQ MQ 的作用 什么是RabbitMQ RabbitMQ的安装 安装 erlang 安装 RabbitMQ 安装 RabbitMQ 管理界面 开放云服务器端口 访问 RabbitMQ 管理界面 RabbitMQ 的用户角色 RabbitMQ的工作流程 Producer 和 Consumer Connection 和 Channel Vi…...
电商项目高级篇06-缓存
电商项目高级篇06-缓存 1、docker下启动redis2、项目整合redis 缓存 流程图: data cache.load(id);//从缓存加载数据 If(data null){ data db.load(id);//从数据库加载数据 cache.put(id,data);//保存到 cache 中 } return data;在我们的单体项目中可以用Map作…...
英伟达发布 Edify 3D 生成模型,可以在两分钟内生成详细的、可用于生产的 3D 资源、生成有组织的 UV 贴图、4K 纹理和 PBR 材质。
英伟达发布 Edify 3D 生成模型,可以利用 Agents 自动判断提示词场景中需要的模型,生成后将他们组合为一个场景。 Edify 3D 可以在两分钟内生成详细的、可用于生产的 3D 资源、生成有组织的 UV 贴图、4K 纹理和 PBR 材质。 相关链接 论文:htt…...
数字电路——触发器2(集成触发器,相互转化)
集成触发器基于RS触发器和钟控触发器,想要了解可以参考文章RS和钟控触发器。 一、集成触发器 这里介绍的集成触发器是将其他类型的触发器与RS触发器相结合 1.1 集成D触发器 1.逻辑符号 区分同步和异步工作: 当同步时,和都为1,…...
拥抱极简主义前端开发:NoCss.js 引领无 CSS 编程潮流
在前端开发的世界里,我们总是在不断追寻更高效、更简洁的方式来构建令人惊艳的用户界面。而今天,我要向大家隆重介绍一款具有创新性的工具 ——NoCss.js,它将彻底颠覆你对传统前端开发的认知,引领我们进入一个全新的无 CSS 编程时…...
CentOS 7 安装部署 KVM
1.关闭虚拟机 打开相关选项 打开虚拟机centos7 连接xshell 测试网络,现在就是没问题的,因为我们要使用网络源 安装 GNOME 桌面环境 安装KVM 模块 安装KVM 调试工具 构建虚拟机的命令行工具 qemu 组件,创建磁盘、启动虚拟机等 输入这条命令,…...
【es6】原生js在页面上画矩形添加选中状态高亮及显示调整大小控制框(三)
接上篇文章,这篇实现下选中当前元素显示调整大小的控制框,点击document取消元素的选中高亮状态效果。 实现效果 代码逻辑 动态生成控制按钮矩形,并设置响应的css // 动态添加一个调整位置的按钮addScaleBtn(target) {const w target.offsetWidth;con…...
适用于学校、医院等低压用电场所的智能安全配电装置
引言 电力,作为一种清洁且高效的能源,极大地促进了现代生活的便捷与舒适。然而,与此同时,因使用不当或维护缺失等问题,漏电、触电事件以及电气火灾频发,对人们的生命安全和财产安全构成了严重威胁…...
通信原理实验:抽样定理实验
目录 一、实验目的和要求 二、实验内容和原理 实验器材 实验原理 三、实验步骤 (一)实验项目一:抽样信号观测及抽样定理验证 四、实验记录与处理 结论: 辅助学习资料: 五、实验结果及分析 一、实验目的和要求 了解抽样定理在通信系统中的重要性。掌握自然抽样及…...
Http 请求协议
HTTP的请求协议 请求数据格式: 请求行 请求数据的第一行,包含请求方式、资源路径、协议及版本。 请求头 从请求数据的第二行,以key: value的格式 常见的请求头 Host:请求的主机名,如:localhost:8080&#x…...
Java中的JSONObject详解
文章目录 Java中的JSONObject详解一、引言二、JSONObject的创建与基本操作1、创建JSONObject2、添加键值对3、获取值 三、JSONObject的高级特性1、遍历JSONObject2、从字符串创建JSONObject3、JSONObject与JSONArray的结合使用4、更新和删除键值对 四、错误处理1. 键值存在性检…...
day01
Hm-Footer.vue <template><div class"hm-footer">我是hm-footer</div></template><script>export default {}</script><style>.hm-footer{height:100px;line-height:100px;text-align:center;font-size:30px;background-…...
shell查看服务器的内存和CPU,实时使用情况
要查看服务器的内存和 CPU 实时使用情况,可以使用以下方法和命令: 1. 使用 top 运行 top 命令以显示实时的系统性能信息,包括 CPU 和内存使用情况。 top按 q 退出。输出内容包括: CPU 使用率:位于顶部,标…...
【后端面试总结】MySQL索引
数据库索引不只一种实现方法,但是其中最具代表性,也是我们面试中遇到最多的无疑是B树。 索引为什么选择B树 数据量很大的查找,是不能直接放入内存的,而是需要什么数据就通过磁盘IO去获得。 红黑树,AVL树等二叉查找树…...
vue3 reactive响应式实现源码
Vue 3 的 reactive 是基于 JavaScript 的 Proxy 实现的,因此它通过代理机制来拦截对象的操作,从而实现响应式数据的追踪。下面是 Vue 3 的 reactive 源码简化版。 Vue 3 reactive 源码简化版 首先,我们需要了解 reactive 是如何工作的&…...
STL之算法概览
目录 算法概览 算法分析与复杂度标识O() STL算法总览 质变算法mutating algorithms----会改变操作对象之值 非质变算法nonmutating algorithms----不改变操作对象之值 STL算法的一般形式 算法的泛化过程 算法概览 算法,问题之解法也。 以有限的步骤࿰…...
数据库中的视图
数据库中的视图 什么是视图创建视图使⽤视图修改数据注意事项 删除视图视图的优点 什么是视图 视图是⼀个虚拟的表,它是基于⼀个或多个基本表或其他视图的查询结果集。视图本⾝不存储数 据,⽽是通过执⾏查询来动态⽣成数据。⽤户可以像操作普通表⼀样使…...
【设计模式】【行为型模式(Behavioral Patterns)】之责任链模式(Chain of Responsibility Pattern)
1. 设计模式原理说明 责任链模式(Chain of Responsibility Pattern) 是一种行为设计模式,它允许你将请求沿着处理者链进行发送。每个处理者都可以处理请求,或者将其传递给链上的下一个处理者。这种模式使得多个对象都有机会处理请…...
Angular面试题汇总系列一
1. 如何理解Angular Signal Angular Signals is a system that granularly tracks how and where your state is used throughout an application, allowing the framework to optimize rendering updates. 什么是信号 信号是一个值的包装器,可以在该值发生变化时…...
【面试分享】主流编程语言的内存回收机制及其优缺点
以下是几种主流编程语言的内存回收机制及其优缺点: 一、Java 内存回收机制: Java 使用自动内存管理,主要通过垃圾回收器(Garbage Collector,GC)来回收不再被使用的对象所占用的内存。Java 的垃圾回收器会定…...
Java中的多线程
文章目录 Java中的多线程一、引言二、多线程的创建和启动1、继承Thread类2、实现Runnable接口 三、线程的常用方法1、currentThread()和getName()2、sleep()和yield()3、join() 四、线程优先级五、使用示例六、总结 Java中的多线程 一、引言 在Java中,多线程编程是…...
TypeError: issubclass() arg 1 must be a class
TypeError: issubclass() arg 1 must be a class 报错代码: import spacy 原因: 库版本错误, 解决方法: pip install typing-inspect0.8.0 typing_extensions4.5.0 感谢作者: langchain TypeError: issubclass() …...
C语言实例之9斐波那契数列实现
1. 斐波那契数列简介 斐波那契数列(Fibonacci sequence),又称黄金分割数列,因数学家莱昂纳多・斐波那契(Leonardo Fibonacci)以兔子繁殖为例子而引入,故又称为 “兔子数列”。 它的特点是从第三…...
Flink 常用问题及常用配置(有用)
一、Flink 常用问题及常用配置 参数 示例 说明 execution.checkpointing.interval 3min Checkpoint 触发间隔 state.backend rocksdb / filesystem 用于设置statebackend类型, 默认会以内存为statebackend(无法支持大状态) taskmanager.memory.jvm-overhead.max 204…...
什么是内网穿透开发
文章目录 前言实现内网穿透的常见技术方法1. 反向代理与端口映射2. 第三方内网穿透服务3. 自建穿透服务4. VPN(虚拟专用网络) 内网穿透开发的关键点1. 安全性2. 性能3. 合法性和合规性 适用场景 前言 内网穿透开发是指将位于内网或防火墙后的应用服务&a…...
RabbitMQ简单应用
概念 RabbitMQ 是一种流行的开源消息代理(Message Broker)软件,它实现了高级消息队列协议(AMQP - Advanced Message Queuing Protocol)。RabbitMQ 通过高效的消息传递机制,主要应用于分布式系统中解耦应用…...
创建HTTPS网站
每天,我们都会听到网络上发生身份盗窃和数据侵权的案例,这导致用户对自己访问的网站更加怀疑。他们开始更加了解自己将个人信息放在哪里以及信任哪些类型的网站。了解如何使网站使用HTTPS变得比以往任何时候都更加重要。 解读缩略词:HTTP与HT…...
【DL笔记】神经网络轻量化(CV方向)的一些论文记录
现在大模型爆火,但俺这种组里只有10系显卡的下水道科研老鼠也要混毕业的,于是选择做小模型(x)。本人纯科研飞舞一个,刚入学有段时间爱看论文,今天有空把那会看到论文总结下。 轻量化,相关文章的…...
计算(a+b)/c的值
计算(ab)/c的值 C语言代码C语言代码Java语言代码Python语言代码 💐The Begin💐点点关注,收藏不迷路💐 给定3个整数a、b、c,计算表达式(ab)/c的值,/是整除运算。 输入 输入仅一行&…...
11.26作业
#include "test.h" #include <myhead.h>int main(int argc, const char *argv[]) {Student students[100]; // 假设最多有100个学生int select 0;int n 0; // 学生数量menu();while (1) {printf("请输入你想要的功能:");scanf("%…...
AdaPipe:动态规划解决显存和GPU在LLM计算中出现气泡问题
目录 AdaPipe:动态规划解决显存和GPU在LLM计算中出现气泡问题 0-5表示不同数据 大的方块表示:管道,便于理解了想成GPU 黄色方块表示显存 Stage表示Attention和FFN layer(Projection和MLP) 重计算和分区策略:细化了Attention和FFN layer Transformer中的管道 AdaPi…...
C++设计模式之组合模式中如何实现同一层部件的有序性
在组合模式中,为了实现同一层上部件的有序性,可以采取以下几种设计方法: 1. 使用有序集合 使用有序集合(如 std::list、std::vector 或其他有序容器)来存储和管理子部件。这种方法可以确保子部件按照特定顺序排列&am…...
QT QRadioButton控件 全面详解
本系列文章全面的介绍了QT中的57种控件的使用方法以及示例,包括 Button(PushButton、toolButton、radioButton、checkBox、commandLinkButton、buttonBox)、Layouts(verticalLayout、horizontalLayout、gridLayout、formLayout)、Spacers(verticalSpacer、horizontalSpacer)、…...
【IEEE独立出版 | 厦门大学主办】第四届人工智能、机器人和通信国际会议(ICAIRC 2024,12月27-29日)
第四届人工智能、机器人和通信国际会议(ICAIRC 2024) 2024 4th International Conference on Artificial Intelligence, Robotics, and Communication 重要信息 会议官网:www.icairc.net 三轮截稿时间:2024年11月30日23:59 录…...
Dubbo的RPC泛化调用
目录 一、RPC泛化调用的应用场景 二、Dubbo RPC泛化调用的实现原理 三、Dubbo RPC泛化调用的实现步骤 四、示例代码 五、泛化调用怎么发现提供该接口的服务及服务的IP和端口? Dubbo的RPC泛化调用是一种在调用方没有服务方提供的API的情况下,对服务方…...
Java面试题、八股文学习之JVM篇
1.对象一定分配在堆中吗?有没有了解逃逸分析技术? 对象不一定总是分配在堆中。在Java等一些高级编程语言中,对象的分配位置可以通过编译器或运行时系统的优化来决定。其中,逃逸分析(Escape Analysis)是用于…...
Apache Maven Assembly 插件简介
Apache Maven Assembly 插件是一个强大的工具,允许您以多种格式(如 ZIP、TAR 和 JAR)创建项目的分发包。 该插件特别适用于将项目与其依赖项、配置文件和其他必要资源一起打包。 通过使用 Maven Assembly 插件,您可以将项目作为…...
3174、清除数字
3174、[简单] 清除数字 1、题目描述 给你一个字符串 s 。你的任务是重复以下操作删除 所有 数字字符: 删除 第一个数字字符 以及它左边 最近 的 非数字 字符。 请你返回删除所有数字字符以后剩下的字符串。 2、解题思路 遍历字符串: 我们需要逐个遍…...
【C#】C# resx方式实现多语言切换(静态切换)
1. 效果 中文界面 英文界面 2. 步骤 1. 添加resx文件 2. Form1.en-GB.resx内容 3. Form1.zh-CN.resx内容 4. Form1.cs修改(重点) using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using Syste…...
鸿蒙系统ubuntu开发环境搭建
在RISC-V等平台移植鸿蒙系统OpenHarmony,需要使用linux环境进行代码的编译,为兼顾日常办公需要,可采用WindowsUbuntu虚拟机的混合开发的环境,通过网络及文件夹共享,在主机和虚拟机之间共享文件数据。 工具准备&#x…...
TCP/IP协议攻击与防范
一、TCP/IP协议攻击介绍 1.1 Internet的结构 LAN:局域网 WAN:广域网 WLAN:无线局域网 私有IP地址与公有IP地址? 私有地址:A类:10.0.0.0~10.255.255.255 B类:172.16.0.0~172.31.255.255…...
1 ISP一键下载
BOOT0BOOT1启动模式说明0X用户Flash用户闪存存储器,也就是Flash启动10系统存储器系统存储器启动,串口下载11SRAM启动SRAM启动,用于在SRAM中调试代码 闪存存储器 是STM32 的内置FLASH,一般使用JTAG或者SWD模式下载程序时,就是下载…...
vue的理解
什么是vue vue是一套用于构建用户界面的渐进式框架,与其他框架不同的是,vue被设计为可以自底向上逐层应用,它也是创建单页面应用的web应用框架。vue的核心库只关注视图层,不仅易上手,还便于与第三方库或既有项目整合。…...
【Leetcode】3206.交替组1
题目描述: https://leetcode.cn/problems/alternating-groups-i/description/?envTypedaily-question&envId2024-11-26 题目示例: 解题思路 思路一: 1.如果color.size()小于等于2,则构不成环,直接返回结果…...
极狐GitLab 17.6 正式发布几十项与 DevSecOps 相关的功能【二】
GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料: 极狐GitLab 官网极狐…...
oracle小技巧-解决特殊密码字符而导致的exp错误
在使用oracle数据库的时候,我们经常会利用exp工具对某些表进行导出。但有些时候,因我们用户密码为安全性设有特殊字符,导致exp导出时候报:“EXP-00056和ORA-12154”,今天我们就分享下如何通过设置符号隔离的小技巧解决…...
tomcat 文件上传 (CVE-2017-12615)
目录 1、漏洞描述 2、访问ip:port 3、漏洞利用 4、Exploit 5、修复建议 1、漏洞描述 Tomcat 是一个小型的轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP 程序的首选。 攻击者将有可能可通过…...
每天五分钟深度学习框架pytorch:卷积神经网络的搭建
本文重点 从本文开始我们将开启卷积神经网络的搭建了,卷积神经网络网络是深度学习中基础的算法模型之一,但是这里我们从实战为主,我们并不会对卷积神经网络详细的介绍,如果不懂得可以看我得《每天五分钟计算机视觉》专栏。 卷积神经网络 卷积神经网络可以认为是多个卷积…...
Opencv+ROS实现颜色识别应用
目录 一、工具 二、原理 概念 本质 三、实践 添加发布话题 主要代码 四、成果 五、总结 一、工具 opencvros ubuntu18.04 摄像头 二、原理 概念 彩色图像:RGB(红,绿,蓝) HSV图像:H࿰…...
JVM详解:垃圾回收机制
java作为大型服务开发的主流语言,其运行会占用大量的内存空间,那么合理的使用有限的服务器资源至关重要。和大多数翻译性语言一样,java的运行环境jvm也内置垃圾回收机制,其通过一些合理的算法组合,定时来对堆中保存的不…...