消息队列-RabbitMQ

2026年9月18日星期五·4061 字·20 分钟·
-浏览量
微服务与中间件消息队列RabbitMQ
AI 摘要- DeepSeek

双击运行otp_win64_24.3.4.6.exe,点击下一步下一步即可,可以更改安装位置,需要注意路径不要有中文或空格,他的作用类似JDK,因为rabbitMQ是erlang语言开发的,所以需要环境支持

消息队列-RabbitMQ - 封面图

消息队列-RabbitMQ#

安装rabbitMQ#

双击运行otp_win64_24.3.4.6.exe,点击下一步下一步即可,可以更改安装位置,需要注意路径不要有中文或空格

他的作用类似JDK,因为rabbitMQ是erlang语言开发的,所以需要环境支持

配置环境变量,在path中配置: 自己安装erlang的路径\bin

image-20230224202431336
image-20230224202431336
image-20230224202301804
image-20230224202301804

双击运行rabbitmq-server-3.10.1.exe,下一步即可,安装好后进入以下目录

image-20230224202733157
image-20230224202733157
在该目录下打开dos窗口,输入以下运行命令

batTerminal window
rabbitmq-plugins enable rabbitmq_management

启动结束后,访问:http://localhost:15672

image-20230224203737805
image-20230224203737805
用户名和密码都是:guest
image-20230224203828259
image-20230224203828259

rabbitMQ的基本概念#

image-20230224210652678
image-20230224210652678

Exchange#

接受生产者发送的消息,并根据binding规则将消息路由给服务器中的队列。

ExchangeType决定了Exchange路由消息的行为。在RabbitMQ中,ExchangeType常用的类型有三种:direct、fanout和topic。

Message Queue#

消息队列。我们发送给RabbitMQ的消息最后都会到达各种queue,并且存储在其中(如果路由找不到对应的queue则数据会丢失),等待消费者来取。

Binding Key#

它表示的是Exchange和Message Queue是通过binding key进行联系的,这个关系是固定。

Routing Key#

生产者在将消息发送给Exchange的时候,一般会指定一个routing key,来指定这个消息的路由规则。这个routing key需要与ExchangeType及binding key联合使用才能生效,我们的生产者只需要通过指定routing key来决定消息流向哪里

RabbitMQ六种工作模式#

创建一个RabbitMQ的项目,用来学习rabbitmq,需要添加依赖

xml
<!--添加RabbitMQ依赖-->
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.12.0</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.6.4</version>
</dependency>

简单模式#

只有一个消费者

image-20230224212545820
image-20230224212545820

生产者#

java
package cn.tedu.rabbitmq.simple;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
//模拟简单模式的生产者
public class Producer {
public static void main(String[] args)throws Exception{
//1.配置RabbitMQ的连接信息
ConnectionFactory cf = new ConnectionFactory();
cf.setHost("127.0.0.1");
cf.setPort(5672);//15672是UI端口,5672是客户端端口(可以省略)
cf.setUsername("guest");
cf.setPassword("guest");
//2.创建连接以及channel
Connection nc = cf.newConnection();
Channel cc = nc.createChannel();
//3.创建队列
/*
第一个参数:队列名称
第二个参数:是否是一个持久队列
第三个参数:是否是一个独占队列
第四个参数:是否自动删除
第五个参数:其他参数属性的设置
*/
cc.queueDeclare("helloworld",false,false,false,null);
//4.准备数据
String msg = "hello world" + System.currentTimeMillis();
//5.发送数据
/*
第一个参数:先忽略
第二个参数:先写成队列名称
第三个参数:其他属性设置
第四个参数:消息数据,需要转成byte[]类型
*/
cc.basicPublish("","helloworld",null,msg.getBytes());
nc.close();
}
}

消费者#

java
package cn.tedu.rabbitmq.simple;
import com.rabbitmq.client.*;
import java.io.IOException;
//简单模式的消费者
public class Consumer {
public static void main(String[] args) throws Exception{
//1.配置连接信息
ConnectionFactory cf = new ConnectionFactory();
cf.setHost("127.0.0.1");
cf.setUsername("guest");
cf.setPassword("guest");
//2.创建连接以及channel
Connection nc = cf.newConnection();
Channel cc = nc.createChannel();
//3.创建队列
//如果该队列已经在服务器中存在,那么会忽略创建该队列的命令
cc.queueDeclare("helloworld",false,false,false,null);
//4.消费消息
//处理数据的回调函数
DeliverCallback deliverCallback = new DeliverCallback() {
@Override
public void handle(String s, Delivery delivery) throws IOException {
byte[] body = delivery.getBody();
String msg = new String(body);
System.out.println("收到了消息:"+msg);
System.out.println("===========================");
}
};
//取消接收数据的回调函数
CancelCallback cancelCallback = new CancelCallback() {
@Override
public void handle(String s) throws IOException {
}
};
cc.basicConsume("helloworld",true,deliverCallback,cancelCallback);
}
}

工作队列模式#

多个消费者,从同一个队列中接受消息

负载均衡,消息会轮询发送给所有消费者

合理的分发消息

  1. 手动ack

    消息回执

    向服务器发送一个通知,告诉服务器一条消息已经处理完毕

    服务器可以通过ack,知道消费者是空闲还是繁忙

  2. qos=1

​ 每次抓取的消息数量

​ 消息处理完毕之前,不会抓取新消息

​ 手动ack模式下才有效

消息持久化:在服务器端,持久保存消息,避免因为服务器宕机而造成消息丢失

  1. 队列持久化: cc.queueDeclare(“队列名”,true,…)
  2. 消息持久化: cc.basocPublish("",“队列名”,MessageProperties.PERSISTENT_TEXT_PLAIN,消息)

生产者#

java
package cn.tedu.rabbitmq.work;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.util.Scanner;
//模拟工作队列模式的生产者
public class Producer {
public static void main(String[] args)throws Exception{
//1.配置RabbitMQ的连接信息
ConnectionFactory cf = new ConnectionFactory();
cf.setHost("127.0.0.1");
cf.setPort(5672);//15672是UI端口,5672是客户端端口(可以省略)
cf.setUsername("guest");
cf.setPassword("guest");
//2.创建连接以及channel
Connection nc = cf.newConnection();
Channel cc = nc.createChannel();
//3.创建队列
/*
第一个参数:队列名称
第二个参数:是否是一个持久队列
第三个参数:是否是一个独占队列
第四个参数:是否自动删除
第五个参数:其他参数属性的设置
*/
cc.queueDeclare("work_queue",false,false,false,null);
//4.准备数据,发送数据
while(true){
System.out.print("输入消息:");
String msg = new Scanner(System.in).nextLine();
if (msg.equals("quit"))
break;
cc.basicPublish("","work_queue",null,msg.getBytes());
}
nc.close();
}
}

消费者#

java
package cn.tedu.rabbitmq.work;
import com.rabbitmq.client.*;
import java.io.IOException;
//工作队列模式的消费者
public class Consumer {
public static void main(String[] args) throws Exception{
//1.配置连接信息
ConnectionFactory cf = new ConnectionFactory();
cf.setHost("127.0.0.1");
cf.setUsername("guest");
cf.setPassword("guest");
//2.创建连接以及channel
Connection nc = cf.newConnection();
Channel cc = nc.createChannel();
//3.创建队列
//如果该队列已经在服务器中存在,那么会忽略创建该队列的命令
cc.queueDeclare("work_queue",false,false,false,null);
//4.消费消息
//处理数据的回调函数
DeliverCallback deliverCallback = new DeliverCallback() {
@Override
public void handle(String s, Delivery delivery) throws IOException {
byte[] body = delivery.getBody();
String msg = new String(body);
System.out.println("收到了消息:"+msg);
//处理消息的时候,遇到一个‘.’,暂停1s,模拟实际处理消息的阻塞场景
for (int i = 0; i < msg.length(); i++) {
//charAt(i)
if(msg.charAt(i)=='.'){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("消息处理完毕");
}
};
//取消接收数据的回调函数
CancelCallback cancelCallback = new CancelCallback() {
@Override
public void handle(String s) throws IOException {
}
};
cc.basicConsume("work_queue",true,deliverCallback,cancelCallback);
}
}

合理分发#

java
package cn.tedu.rabbitmq.work;
import com.rabbitmq.client.*;
import java.io.IOException;
//工作队列模式的消费者
public class Consumer {
public static void main(String[] args) throws Exception{
//1.配置连接信息
ConnectionFactory cf = new ConnectionFactory();
cf.setHost("127.0.0.1");
cf.setUsername("guest");
cf.setPassword("guest");
//2.创建连接以及channel
Connection nc = cf.newConnection();
Channel cc = nc.createChannel();
//3.创建队列
//如果该队列已经在服务器中存在,那么会忽略创建该队列的命令
cc.queueDeclare("work_queue",false,false,false,null);
//4.消费消息
//处理数据的回调函数
DeliverCallback deliverCallback = new DeliverCallback() {
@Override
public void handle(String s, Delivery delivery) throws IOException {
byte[] body = delivery.getBody();
String msg = new String(body);
System.out.println("收到了消息:"+msg);
//处理消息的时候,遇到一个‘.’,暂停1s,模拟实际处理消息的阻塞场景
for (int i = 0; i < msg.length(); i++) {
//charAt(i)
if(msg.charAt(i)=='.'){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("消息处理完毕");
//发送消息确认(消息回执)
//第一个参数:消息的标签,需要从消息中获取
//第二个参数:是否确认多条信息,false,只确认一条消息
cc.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
}
};
//取消接收数据的回调函数
CancelCallback cancelCallback = new CancelCallback() {
@Override
public void handle(String s) throws IOException {
}
};
//第二个参数:ack的设置,默认是autoAck,false是手动ack
//设置消费者每次只获取一条消息
cc.basicQos(1);
cc.basicConsume("work_queue",false,deliverCallback,cancelCallback);
}
}

持久化#

如果消息保存在服务器端的内存中,是不安全的,如果服务器宕机,信息会丢失

batTerminal window
停止rabbitmq服务:rabbitmq-service stop或者rabbitmqctl stop
启动rabbitmq服务:rabbitmq-service start

消息数据持久化、消息队列持久化

但是需要注意持久化队列时,不能直接修改队列属性,因为队列一定创建属性就固定了,不可以进行修改

可以选择新建一个别名队列或者删除该队列重新创建

队列持久化:cc.queueDeclare(“task_queue”,true,false,false,null);

数据持久化:cc.basicPublish("",“task_queue”, MessageProperties.PERSISTENT_TEXT_PLAIN,msg.getBytes());

发布订阅模式#

把消息群发给所有消费者,同一条消息所有消费者都可以收到

fanout类型的交换机

生产者:定义交换机,向交换机发送数据

消费者:定义交换机,定义自已独占的非持久的自动删除随机队列,绑定,正常从随机队列中接受数据

生产者#

java
package cn.tedu.rabbitmq.publishsubscribe;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.util.Scanner;
//模拟发布订阅模式的生产者
public class Producer {
public static void main(String[] args) throws Exception{
//1.配置RabbitMQ的连接信息
ConnectionFactory cf = new ConnectionFactory();
cf.setHost("127.0.0.1");
cf.setPort(5672);//15672是UI端口,5672是客户端端口(可以省略)
cf.setUsername("guest");
cf.setPassword("guest");
//2.创建连接以及channel
Connection nc = cf.newConnection();
Channel cc = nc.createChannel();
//3.定义交换机
//如果服务器中没有,就创建,有就直接使用
//第一个参数:交换机名称
//第二个参数:交换机类型
cc.exchangeDeclare("ps_exchange","fanout");
//4.向交换机发送数据,交换机只是接受发送数据,并不保存数据
//如果没有消费者接受,数据会丢失
while (true){
System.out.print("输入消息:");
String msg = new Scanner(System.in).nextLine();
if (msg.equals("quit"))
break;
cc.basicPublish("ps_exchange","",null,msg.getBytes());
}
nc.close();
}
}

消费者#

java
package cn.tedu.rabbitmq.publishsubscribe;
import com.rabbitmq.client.*;
import java.io.IOException;
//发布订阅模式的消费者
public class Consumer {
public static void main(String[] args) throws Exception{
//1.配置RabbitMQ的连接信息
ConnectionFactory cf = new ConnectionFactory();
cf.setHost("127.0.0.1");
cf.setPort(5672);//15672是UI端口,5672是客户端端口(可以省略)
cf.setUsername("guest");
cf.setPassword("guest");
//2.创建连接以及channel
Connection nc = cf.newConnection();
Channel cc = nc.createChannel();
//3.定义交换机
//如果服务器中没有,就创建,有就直接使用
//第一个参数:交换机名称
//第二个参数:交换机类型
cc.exchangeDeclare("ps_exchange","fanout");
//4.定义队列--随机队列名,否持久,独占、自动删除的
String queue = cc.queueDeclare().getQueue();//无参构造就可以满足我们的需求
//5.绑定交换机和队列
/*
第一个参数:队列名称
第二个参数:交换机名称
第三个参数:队列和交换机绑定的关系
*/
cc.queueBind(queue,"ps_exchange","");
//6.处理接收到的消息
//处理数据
DeliverCallback deliverCallback = new DeliverCallback() {
@Override
public void handle(String s, Delivery delivery) throws IOException {
byte[] body = delivery.getBody();
String msg = new String(body);
System.out.println("收到:"+msg);
System.out.println("消息处理完毕");
}
};
//取消数据时的回调函数
CancelCallback cancelCallback = new CancelCallback() {
@Override
public void handle(String s) throws IOException {
}
};
cc.basicConsume(queue,true,deliverCallback,cancelCallback);
}
}

路由模式#

通过关键字匹配,来决定把消息发送到哪个队列

生产者:定义direct类型的交换机,向交换机发送数据并携带路由键

消费者:定义交换机,定义队列,用绑定键来绑定交换机和队列,正常接收消息

生产者#

java
package cn.tedu.rabbitmq.route;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.util.Scanner;
//模拟路由模式的生产者
public class Producer {
public static void main(String[] args) throws Exception{
//1.配置RabbitMQ的连接信息
ConnectionFactory cf = new ConnectionFactory();
cf.setHost("127.0.0.1");
cf.setPort(5672);//15672是UI端口,5672是客户端端口(可以省略)
cf.setUsername("guest");
cf.setPassword("guest");
//2.创建连接以及channel
Connection nc = cf.newConnection();
Channel cc = nc.createChannel();
//3.定义direct类型的交换机
cc.exchangeDeclare("route_exchange", BuiltinExchangeType.DIRECT);
//4.发送消息,携带路由键
while(true){
Scanner scanner = new Scanner(System.in);
System.out.print("输入消息:");
String msg = scanner.nextLine();
System.out.print("路由键:");
String routingKey = scanner.nextLine();
if(msg.equals("quit"))
break;
cc.basicPublish("route_exchange",routingKey,null,msg.getBytes());
System.out.println("消息发送成功");
}
nc.close();
}
}

消费者#

java
package cn.tedu.rabbitmq.route;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.Scanner;
//模拟路由模式的消费者
public class Consumer {
public static void main(String[] args) throws Exception{
//1.配置RabbitMQ的连接信息
ConnectionFactory cf = new ConnectionFactory();
cf.setHost("127.0.0.1");
cf.setPort(5672);//15672是UI端口,5672是客户端端口(可以省略)
cf.setUsername("guest");
cf.setPassword("guest");
//2.创建连接以及channel
Connection nc = cf.newConnection();
Channel cc = nc.createChannel();
//3.定义direct类型的交换机
cc.exchangeDeclare("route_exchange", BuiltinExchangeType.DIRECT);
//4.定义队列
String queue = cc.queueDeclare().getQueue();
//5.绑定交换机和队列(重复绑定多次)
System.out.print("输入绑定键,用空格隔开:");
String bindingKeys = new Scanner(System.in).nextLine();
String[] keys = bindingKeys.split("\\s+");
for (String bindingKey : keys) {
cc.queueBind(queue,"route_exchange",bindingKey);
}
//处理数据
DeliverCallback deliverCallback = new DeliverCallback() {
@Override
public void handle(String s, Delivery delivery) throws IOException {
String msg = new String(delivery.getBody());
String routingKey = delivery.getEnvelope().getRoutingKey();
System.out.println(msg+"-"+routingKey);
System.out.println("====================");
}
};
CancelCallback cancelCallback = new CancelCallback() {
@Override
public void handle(String s) throws IOException {
}
};
cc.basicConsume(queue,true,deliverCallback,cancelCallback);
}
}

主题模式#

和路由模式相同,具有特殊的关键字规则

topic类型的交换机实现这种特殊路由规则

aaa.bbb.ccc.ddd

*.ccc.ddd.eee

#.ddd

”*“可以通配单个单词

”#“可以通配零个或多个单词

生产者#

java
package cn.tedu.rabbitmq.topic;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.util.Scanner;
//模拟主题模式的生产者
public class Producer {
public static void main(String[] args) throws Exception{
//1.配置RabbitMQ的连接信息
ConnectionFactory cf = new ConnectionFactory();
cf.setHost("127.0.0.1");
cf.setPort(5672);//15672是UI端口,5672是客户端端口(可以省略)
cf.setUsername("guest");
cf.setPassword("guest");
//2.创建连接以及channel
Connection nc = cf.newConnection();
Channel cc = nc.createChannel();
//3.定义direct类型的交换机
cc.exchangeDeclare("topic_exchange", BuiltinExchangeType.TOPIC);
//4.发送消息,携带路由键
while(true){
Scanner scanner = new Scanner(System.in);
System.out.print("输入消息:");
String msg = scanner.nextLine();
System.out.print("路由键:");
String routingKey = scanner.nextLine();
if(msg.equals("quit"))
break;
cc.basicPublish("topic_exchange",routingKey,null,msg.getBytes());
System.out.println("消息发送成功");
}
nc.close();
}
}

消费者#

java
package cn.tedu.rabbitmq.topic;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.Scanner;
//模拟主题模式的消费者
public class Consumer {
public static void main(String[] args) throws Exception{
//1.配置RabbitMQ的连接信息
ConnectionFactory cf = new ConnectionFactory();
cf.setHost("127.0.0.1");
cf.setPort(5672);//15672是UI端口,5672是客户端端口(可以省略)
cf.setUsername("guest");
cf.setPassword("guest");
//2.创建连接以及channel
Connection nc = cf.newConnection();
Channel cc = nc.createChannel();
//3.定义direct类型的交换机
cc.exchangeDeclare("topic_exchange", BuiltinExchangeType.TOPIC);
//4.定义队列
String queue = cc.queueDeclare().getQueue();
//5.绑定交换机和队列(重复绑定多次)
System.out.print("输入绑定键,用空格隔开:");
String bindingKeys = new Scanner(System.in).nextLine();
String[] keys = bindingKeys.split("\\s+");
for (String bindingKey : keys) {
cc.queueBind(queue,"topic_exchange",bindingKey);
}
//处理数据
DeliverCallback deliverCallback = new DeliverCallback() {
@Override
public void handle(String s, Delivery delivery) throws IOException {
String msg = new String(delivery.getBody());
String routingKey = delivery.getEnvelope().getRoutingKey();
System.out.println(msg+"-"+routingKey);
System.out.println("====================");
}
};
CancelCallback cancelCallback = new CancelCallback() {
@Override
public void handle(String s) throws IOException {
}
};
cc.basicConsume(queue,true,deliverCallback,cancelCallback);
}
}

RPC模式#

实现原理

  1. 两个队列

    调用队列

    返回队列:每个客户端,都需要有自己的返回队列

  2. 返回队列的队列名

    在调用消息数据中,携带返回队列名

    根据返回队列名,向正确的返回队列来发送计算结果

  3. 关联ID

    用来匹配计算结果和调用

    如果连续发送多次调用,获得计算结果时,需要直到这个节骨欧式按一次调用的结果

    客户端发送调用时,携带一个关联ID

    服务器端返回结果时,也携带这个关联ID

客户端:多线程异步处理结果

  1. 主线程

    发送调用信息

    需要计算结果时,要取结果

  2. 次线程:等待接受结果

  3. 线程之间传递数据,可以使用BlockingQueue

    集合工具

    这个集合中,添加了线程的等待和通知

    如果没有数据,取数据时会暂停等待

    有多个子类:比如ArrayBlockingQueue

服务器#

java
package cn.tedu.rabbitmq.rpc;
import com.rabbitmq.client.*;
import com.rabbitmq.client.AMQP.BasicProperties;
import java.io.IOException;
public class RPCServer {
public static void main(String[] args) throws Exception{
ConnectionFactory cf = new ConnectionFactory();
cf.setHost("127.0.0.1");
cf.setPort(5672);//15672是UI端口,5672是客户端端口(可以省略)
cf.setUsername("guest");
cf.setPassword("guest");
Connection nc = cf.newConnection();
Channel cc = nc.createChannel();
//1.接受客户端发送的调用信息(正整数n)
//2.执行算法求第n个斐波那契数
//3.向客户端发送计算结果
//定义调用队列
cc.queueDeclare("rpc_queue",false,false,false,null);
//从调用队列中取调用信息
DeliverCallback deliverCallback = new DeliverCallback() {
@Override
public void handle(String s, Delivery delivery) throws IOException {
//从delivery取出正整数n
String msg = new String(delivery.getBody());
String replyTo = delivery.getProperties().getReplyTo();//返回队列名
String correlationId = delivery.getProperties().getCorrelationId();//关联id
long fbnqs = fbnqs(Integer.parseInt(msg));
BasicProperties basicProperties = new BasicProperties.Builder().correlationId(correlationId).build();
cc.basicPublish("",replyTo,basicProperties,(""+fbnqs).getBytes());
}
};
CancelCallback cancelCallback = new CancelCallback() {
@Override
public void handle(String s) throws IOException {
}
};
cc.basicConsume("rpc_queue",true,deliverCallback,cancelCallback);
}
//服务:求第n个斐波那契数
//1 1 2 3 5 8 13 21 34 55 ......
//递归效率低,可以用来模拟服务器端的耗时运算
static long fbnqs(int n){
if(n==1 || n==2)
return 1;
return fbnqs(n-1)+fbnqs(n-2);
}
}

客户端#

java
package cn.tedu.rabbitmq.rpc;
import com.rabbitmq.client.*;
import com.rabbitmq.client.AMQP.BasicProperties;
import java.io.IOException;
import java.util.Scanner;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class RPCClient {
static BlockingQueue<Long> q = new ArrayBlockingQueue<Long>(10);
public static void main(String[] args) throws Exception{
System.out.print("输入求第几个斐波那契数:");
int n = new Scanner(System.in).nextInt();
long fbnqs = fbnqs(n);
System.out.println("第"+n+"个的斐波那契数是:"+fbnqs);
}
//异步调用服务器,从服务器中获取结果
private static long fbnqs(int n) throws Exception{
ConnectionFactory cf = new ConnectionFactory();
cf.setHost("127.0.0.1");
cf.setPort(5672);//15672是UI端口,5672是客户端端口(可以省略)
cf.setUsername("guest");
cf.setPassword("guest");
Connection nc = cf.newConnection();
Channel cc = nc.createChannel();
//定义调用队列
cc.queueDeclare("rpc_queue",false,false,false,null);
//返回队列
String replyTo = cc.queueDeclare().getQueue();
//关联id
String cid = UUID.randomUUID().toString();
BasicProperties basicProperties = new BasicProperties.Builder()
.replyTo(replyTo)
.correlationId(cid)
.build();
cc.basicPublish("","rpc_queue",basicProperties,(""+n).getBytes());
//模拟执行其他运算,不等待计算结果
System.out.println("调用消息已经发送");
System.out.println("模拟执行其他运算,不立即等待计算结果");
//获取计算结果
DeliverCallback deliverCallback = new DeliverCallback() {
@Override
public void handle(String s, Delivery delivery) throws IOException {
//处理数据之前,先对比关联id
if(cid.equals(delivery.getProperties().getCorrelationId())){
String msg = new String(delivery.getBody());
long fbnqs = Integer.parseInt(msg);
q.offer(fbnqs);
cc.getConnection().close();
}
}
};
CancelCallback cancelCallback = new CancelCallback() {
@Override
public void handle(String s) throws IOException {
}
};
cc.basicConsume(replyTo,true,deliverCallback,cancelCallback);
return q.take();
}
}
消息队列-RabbitMQ
https://www.cati.cc.cd/posts/mq-rabbitmq-notes/
作者
MIAOWU
发布于
2026-09-18
许可协议
CC BY-NC-SA 4.0

评论区

动作模组
等待模型加载…
看板娘
公告
公告大版本更新

一口气全面统一博客样式,移除部分冗余导航页面,更专注内容展示。

公告稳定性修复一批

统一Swup生命周期(BUG更少了、牺牲了首屏部分性能)、升级astro 7(构建速度翻倍)、文章封面图片加载(更流畅)、更换音乐播放器 API(更稳定)等多个问题,站点更稳了。

公告互换友链

欢迎各位大佬互换友链,要求内容原创、稳定更新。申请前请先看友链页的说明,期待和你交换链接。

查看详情
公告关于我的介绍

欢迎来到我的博客,我是深耕java、python和agent技术开发。热爱技术、持续学习,欢迎同好交流探讨。

查看详情
音乐
封面

音乐

暂未播放

0:00
0:00
暂无歌词

日历

正在加载日历...

--

    最近节日

    正在加载日历...
    ----

    最近生日/纪念日

    正在加载日历...
    ----
    距月底--
    距年底--

    隐私政策

    更新日期: 2026 年 7 月 15 日
    生效日期: 2026 年 7 月 15 日

    适用范围#

    本政策适用于 MiaoWu 的博客(以下简称“本站”)。本站是个人博客,用于发布和分享内容;不提供账户注册、支付、定位或广告投放服务。访问本站、发表文章评论或在留言板留言前,请阅读本政策。

    信息收集与使用#

    本站只在提供内容、评论和留言功能,以及维护站点安全所需的范围内处理信息。

    • 访问与统计信息:访问页面时,统计服务可能处理访问时间、页面地址、来源页、浏览器和设备相关信息,用于了解内容访问情况、排查故障和改进站点。
    • 评论信息:使用文章评论功能时,Waline 可能处理您主动提交的昵称、邮箱、站点链接和评论内容;还可能处理 IP 地址等必要信息,用于防止垃圾评论、滥用和维护服务安全。评论内容、昵称和站点链接(如填写)可能公开展示在文章下方;邮箱不会公开展示。
    • 留言信息:留言板使用 Waline /guestbook/ 频道。Waline 可能处理您主动提交的昵称、可选邮箱、站点链接、留言内容和图片,以及浏览器、操作系统、IP 地址等必要的反滥用信息。默认情况下,留言图片以内嵌数据随留言提交;如站点维护者配置了远程图片上传接口,图片会先发送至该接口并在留言中保存返回的图片地址。留言内容、昵称、图片和站点链接(如填写)可能公开展示;邮箱和 IP 地址不会在留言板公开展示。

    请不要在评论或留言中提交身份证件、银行卡、住址、密码或其他不必要的敏感个人信息。

    第三方服务#

    为实现本站功能,以下第三方会在各自服务范围内处理相关数据:

    • Umami:用于匿名化的网站访问统计和出站链接点击统计,帮助我了解本站的使用情况。
    • Waline:用于文章评论、留言板及访问量统计。服务会按照其自身规则处理您在评论或留言时提交的信息及必要的反滥用信息。
    • Cloudflare:可为本站提供静态资源分发和域名基础设施。
    • unpkg:用于加载 Waline 的前端脚本、样式和表情资源;请求这些资源时,您的浏览器会与该服务建立连接。

    第三方服务可能有独立的隐私政策和数据保存规则。请在使用相关功能前查阅其规则;本站无法控制其独立的数据处理活动。

    本站主要使用浏览器本地存储(Local Storage 或 Session Storage)保存使用偏好,例如主题颜色、明暗模式、文章列表视图和音乐播放设置。留言板会在本地保存匿名资料、未发送草稿和登录状态,以便恢复输入与会话;管理员登录状态仅保存在当前会话。

    本站不主动设置用于广告定向的第一方 Cookie。评论、统计或资源服务可能按照其自身规则使用 Cookie 或类似技术。您可以通过浏览器设置查看、删除或限制 Cookie 和本地存储;清除后,部分偏好或互动状态可能会恢复为默认值,评论功能也可能受到影响。

    信息公开、保存与安全#

    评论和留言属于公开互动内容,提交后可能被搜索引擎收录、被他人引用或在缓存中短暂保留。请谨慎决定发布内容。除非您提出删除请求、内容违反规则或法律法规另有要求,公开内容会持续保留以维持讨论上下文。

    本站会采取合理措施保护数据安全,包括使用 HTTPS、输入校验、内容转义和访问频率限制。但互联网传输和第三方服务均无法保证绝对安全,请理解并自行承担公开发布信息的相应风险。

    你的权利#

    你可以通过 996491835@qq.com 联系我,申请查询、更正或删除由本站直接保存的评论、留言或相关公开内容。为保护他人权益,请在请求中提供足以定位内容的信息,并说明你与该内容的关系;必要时可能需要进行合理核验。

    对于由 Waline、Umami、Cloudflare 或 unpkg 独立处理的数据,你也可以直接向对应服务提供方行使相关权利。删除公开评论或留言后,第三方缓存、搜索引擎索引或他人转载的副本可能无法立即同步删除。

    未成年人条款#

    未满 14 周岁的未成年人应在监护人同意和指导下使用本站的评论、留言等互动功能。监护人如发现未成年人未经同意提交了个人信息,可通过上述联系方式与我联系,我会在合理范围内协助处理。

    政策更新与联系#

    我可能因本站功能或适用规则变化更新本政策,更新后的版本将在本站公布并标明日期。继续使用相关功能即表示你已阅读并理解更新后的政策。

    如对本政策或数据处理有疑问,请联系 996491835@qq.com。

    用户协议

    更新日期: 2026 年 5 月 19 日
    生效日期: 2026 年 5 月 19 日

    适用范围#

    本协议适用于你访问 MiaoWu 的博客,以及使用文章评论、留言板等互动功能的行为。继续浏览本站或提交评论、留言,即表示你已阅读、理解并同意遵守本协议及本站的隐私政策。

    评论及留言规则#

    请在交流中保持友善、理性和尊重。你不得利用本站发布、传播或实施以下行为:

    • 发布任何违反中华人民共和国法律法规的内容。
    • 发布任何侵犯他人合法权益的内容,包括但不限于隐私、名誉、肖像、著作权、商标权和其他知识产权。
    • 恶意攻击、辱骂、骚扰、威胁、歧视其他用户或任何第三方。
    • 发布垃圾广告、恶意推广、刷屏、灌水,或与讨论主题明显无关的重复内容。
    • 利用本站进行网络诈骗、钓鱼、传播恶意软件,或发布可能危害网络和信息安全的内容。
    • 绕越或试图绕越本站的审核、限流、封禁等管理措施。
    • 冒充他人、伪造身份,或收集、公开他人的个人信息。

    内容与访问管理#

    你应对自己发布的评论和留言负责,并保证拥有发布该等内容所需的合法权利。论坛管理员有权在不另行通知的情况下删除违规内容、限制或封禁违规账号,或限制其继续使用本站互动功能。

    如发现涉嫌违法犯罪、严重侵权或危及本站安全的内容,本站可保留相关记录,并在法律法规要求或必要时向有关部门提供协助。对管理措施有疑问时,可通过文末联系方式说明情况;本站会结合实际情况处理,但不承诺恢复已删除内容或访问权限。

    知识产权与内容授权#

    本站原创文章、页面设计和其他受保护内容的权利归作者或权利人所有。未经授权,请勿复制、转载、镜像或用于商业用途;法律法规允许的合理使用除外。

    你发布评论或留言时,授予本站为展示、存储、备份、审核、删除和维护互动功能所必需的非独占、免费的使用许可。该许可不改变你对原创内容依法享有的权利。

    免责声明#

    本站内容仅用于个人记录、学习交流和一般信息参考,不构成任何专业意见、承诺或担保。你应结合自身情况独立判断,并对据此采取的行动负责。

    评论、留言和外部链接中的内容由其发布者或运营者负责,不代表本站立场。本站会在合理范围内处理明显违规内容,但不保证所有内容均及时发现,也不对第三方网站的可用性、内容、安全性或隐私实践承担责任。

    因网络故障、不可抗力、第三方服务异常、维护升级或超出合理控制范围的原因导致本站暂时无法访问、内容延迟或数据丢失的,本站会尽力恢复,但不承担由此产生的间接损失。

    未成年人条款#

    未满 14 周岁的未成年人应在监护人同意和指导下使用评论、留言等互动功能。监护人应协助未成年人理解本协议,并对其使用行为进行必要的引导。

    其他条款#

    我可以根据本站功能、管理需要或法律法规变化更新本协议,更新后的版本将在本站公布并标明日期。继续使用本站即视为接受更新后的协议。

    本协议的订立、执行和解释适用中华人民共和国法律。因本协议或使用本站产生争议时,双方应先友好协商;协商不成的,依法向有管辖权的人民法院解决。

    如对本协议或内容管理有疑问,请联系 996491835@qq.com。

    复制成功,转载请标注本文地址