MQ和RabbitMQ的概述
什么是MQ
MQ就是消息队列(Message Queue),它是一种消息中间件,主要用于在不同系统,进程服务之间传递消息。
举例:就像我们在点外卖时,我们相当于生产者,外卖骑手相当于消费者,外卖平台则相当于MQ,这样订单就可以先排队,然后再由骑手慢慢的接单进行派送
MQ的核心作用
异步处理:
在业务的处理中,一些操作可能十分的耗时,但是不需要立即的进行返回,我们可以借助MQ对这些消息进行异步化,如:用户注册后发送消息或者邮箱进行通知
系统解耦:
系统之间通过消息交互,不直接的进行依赖,在传统的系统中,模块之间是经常进行直接调用的,但是这样会导致高耦合,系统稳定性差,使用MQ后,我们在中间加一层消息队列,就算其中一个系统挂了,消息仍然存储在MQ中,不会丢失。
削峰填谷:
把高并发的流量转为平稳的消费,在高并发系统中,请求量不稳定 ,有高峰有低谷,如果系统直接处理所有请求,可能会被瞬间打垮,引入MQ后,暂储存所有的请求,后端从队列中按系统能力稳定消费;短时间内请求暴增也不会冲垮数据库
可靠的传输:
确保消息不会丢失或重复。
RabbitMQ
而RabbitMQ就是MQ的一种具体实现,基于AMQP协议实现的消息队列
AMQP协议:是一种面向消息中间件的通信协议标准

RabbitMQ的工作流程

RabbitMQ是一个消息中间键,也是一个消费者生产者模型,负责接收,存储并转发消息
Producer:生产者,也是RabbitMQ Server的客户端,向RabbitMQ发送消息
Customer:消费者,也是RabbitMQ Server的客户端,向RabbitMQ接收(消费)消息
Broker:接收和存储,路由,传递消息的核心组件,相当于一个消息的中转站
Connection:是属于客户端和RabbitMQ服务器之间的一个TCP连接,负责传送客户端和服务器之间的所有数据和控制信息
Channel:属于Connection上的一个抽象层,在RabbitMQ中,一个TCP有多个Channel,每个Channel都是独⽴的虚拟连接.消息的发送和接收都是基于Channel的
Virtual host(虚拟机):为消息队列提供了一种逻辑上的隔离机制,是 RabbitMQ 内部用于隔离不同应用或租户的独立命名空间,Broker是一栋大楼,而虚拟机就是这栋大楼里的独立房间**。**
Queue(队列):是RabbitMQ中的内部对象,用于存储消息,多个消费者可以订阅同一个队列
Exchange(交换机):它负责接收⽣产者发送的消息,并根据特定的规则 把这些消息路由到⼀个或多个Queue列中
虚拟机,交换机,队列之间的关系

Web页面




RabbitMQ的快速上手
引入其依赖
java
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.7.3</version>
</dependency>
生产者(Producer)
java
public class producerDemo {
public static void main(String[] args) throws IOException, TimeoutException {
// 1.建立连接
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("你的IP地址");
connectionFactory.setPort(5672);
connectionFactory.setUsername("你的用户名");
connectionFactory.setPassword("你的密码");
connectionFactory.setVirtualHost("你的虚拟机");
Connection connection= connectionFactory.newConnection();
// 2.开启信道
Channel channel=connection.createChannel();
// 申明队列,使用的是内置的交换机
// 如果队列不存在,则创建队列,否则则不创建
channel.queueDeclare("666",true,false,false,null);
for (int i = 0; i < 8; i++) {
String meg="测试一下消息队列的生产者";
channel.basicPublish("","666",null,meg.getBytes());
}
System.out.println("消息发送成功");
channel.close();
connection.close();
}
}
消费者(Customer)
java
public class ConsumerDemo {
public static void main(String[] args) throws IOException, TimeoutException {
// 1.建立连接
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("你的IP地址");
connectionFactory.setPort(5672);
connectionFactory.setUsername("你的用户名");
connectionFactory.setPassword("你的密码");
connectionFactory.setVirtualHost("你的虚拟机");
Connection connection= connectionFactory.newConnection();
// 2.创建channel
Channel channel=connection.createChannel();
// 3.声明队列
// channel.queueDeclare("666",true,false,false,null);
// 4.消费消息
DefaultConsumer consumer=new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("接收消息"+new String(body));
}
};
channel.basicConsume("666",true,consumer);
System.out.println("消费消息成功");
// 5.释放资源
channel.close();
connection.close();
}
}
生产者

消费者

在web页面中队列的显示


RabbitMQ的七种工作模式
1.简单模式

2.工作队列
⼀个⽣产者P,多个消费者C1,C2.在多个消息的情况下,队列会将消息分派给不同的消费者,每个消费者都会接收到不同的消息

3.Publish/Subscribe (发布订阅模式)
⽣产者将消息发送到Exchange,由交换机将消息按⼀定规则路由到⼀个或多个队列中

生产者
java
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException {
// 1.建立连接
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost(Constants.HOST);
connectionFactory.setPort(Constants.PORT);
connectionFactory.setUsername(Constants.USER_NAME);
connectionFactory.setPassword(Constants.PASSWORD);
connectionFactory.setVirtualHost(Constants.VIRTUAL);
Connection connection= connectionFactory.newConnection();
// 2.开启信道
Channel channel=connection.createChannel();
// 3.申明交换机
channel.exchangeDeclare(Constants.EXCHANGE_NAME, BuiltinExchangeType.FANOUT,true);
// 申明队列
channel.queueDeclare(Constants.FANOUT_QUEUE_NAME1,true,false,false,null);
channel.queueDeclare(Constants.FANOUT_QUEUE_NAME2,true,false,false,null);
// 交换机和队列进行绑定
channel.queueBind(Constants.FANOUT_QUEUE_NAME1,Constants.EXCHANGE_NAME,"");
channel.queueBind(Constants.FANOUT_QUEUE_NAME2,Constants.EXCHANGE_NAME,"");
// 发送消息
String msg="消息发送成功";
channel.basicPublish("",Constants.EXCHANGE_NAME,null,msg.getBytes());
// 消息发送成功
System.out.println("消息发送成功");
channel.close();
connection.close();
}
}
消费者1
java
public class customer1 {
public static void main(String[] args) throws IOException, TimeoutException {
// 1.建立连接
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost(Constants.HOST);
connectionFactory.setPort(Constants.PORT);
connectionFactory.setUsername(Constants.USER_NAME);
connectionFactory.setPassword(Constants.PASSWORD);
connectionFactory.setVirtualHost(Constants.VIRTUAL);
Connection connection= connectionFactory.newConnection();
// 2.开启信道
Channel channel=connection.createChannel();
// 3. 申明交换机
channel.exchangeDeclare(Constants.EXCHANGE_NAME, BuiltinExchangeType.FANOUT,true);
// 4.申明队列
channel.queueDeclare(Constants.FANOUT_QUEUE_NAME1,true,false,false,null);
// 5.消费消息
DefaultConsumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费消息+fanout+queue_name1"+new String(body));
}
};
channel.basicConsume(Constants.FANOUT_QUEUE_NAME1,true,consumer);
System.out.println("消息消费成功");
}
}

消费者2
java
public class customer2 {
public static void main(String[] args) throws IOException, TimeoutException {
// 1.建立连接
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost(Constants.HOST);
connectionFactory.setPort(Constants.PORT);
connectionFactory.setUsername(Constants.USER_NAME);
connectionFactory.setPassword(Constants.PASSWORD);
connectionFactory.setVirtualHost(Constants.VIRTUAL);
Connection connection= connectionFactory.newConnection();
// 2.开启信道
Channel channel=connection.createChannel();
// 申明交换机
channel.exchangeDeclare(Constants.EXCHANGE_NAME, BuiltinExchangeType.FANOUT,true);
// 申明队列
channel.queueDeclare(Constants.FANOUT_QUEUE_NAME2,true,false,false,null);
DefaultConsumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消息消费成功 fanout queue_name2"+new String(body));
}
};
channel.basicConsume(Constants.FANOUT_QUEUE_NAME2,true,consumer);
System.out.println("消息消费成功");
}
}

4.Routing(路由模式)

生产者
java
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException {
// 1.建立连接
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost(Constants.HOST);
connectionFactory.setPort(Constants.PORT);
connectionFactory.setUsername(Constants.USER_NAME);
connectionFactory.setPassword(Constants.PASSWORD);
connectionFactory.setVirtualHost(Constants.VIRTUAL);
Connection connection= connectionFactory.newConnection();
// 2.开启信道
Channel channel=connection.createChannel();
// 申明交换机
channel.exchangeDeclare(Constants.DIRECT_EXCHANGE_NAME,BuiltinExchangeType.DIRECT,true);
// 申明队列
channel.queueDeclare(Constants.DIRECT_QUEUE_NAME1,true,false,false,null);
channel.queueDeclare(Constants.DIRECT_QUEUE_NAME2,true,false,false,null);
// 队列的绑定
channel.queueBind(Constants.DIRECT_QUEUE_NAME1,Constants.DIRECT_EXCHANGE_NAME,"a");
channel.queueBind(Constants.DIRECT_QUEUE_NAME2,Constants.DIRECT_EXCHANGE_NAME,"a");
channel.queueBind(Constants.DIRECT_QUEUE_NAME2,Constants.DIRECT_EXCHANGE_NAME,"b");
channel.queueBind(Constants.DIRECT_QUEUE_NAME2,Constants.DIRECT_EXCHANGE_NAME,"c");
String msg="消息的发送 + direct + a ";
String msg1="消息的发送 + direct + b ";
String msg2="消息的发送 + direct + c ";
channel.basicPublish(Constants.DIRECT_EXCHANGE_NAME,"a",null,msg.getBytes());
channel.basicPublish(Constants.DIRECT_EXCHANGE_NAME,"b",null,msg1.getBytes());
channel.basicPublish(Constants.DIRECT_EXCHANGE_NAME,"c",null,msg2.getBytes());
// System.out.println("消息发送成功");
channel.close();
connection.close();
}
}
消费者1
java
public class Customer1 {
public static void main(String[] args) throws IOException, TimeoutException {
// 1.建立连接
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost(Constants.HOST);
connectionFactory.setPort(Constants.PORT);
connectionFactory.setUsername(Constants.USER_NAME);
connectionFactory.setPassword(Constants.PASSWORD);
connectionFactory.setVirtualHost(Constants.VIRTUAL);
Connection connection= connectionFactory.newConnection();
// 2.开启信道
Channel channel=connection.createChannel();
// 创建队列
channel.queueDeclare(Constants.DIRECT_QUEUE_NAME1,true,false,false,null);
// 消费消息
DefaultConsumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("已经接收到消息"+new String(body));
}
};
channel.basicConsume(Constants.DIRECT_QUEUE_NAME1,true,consumer);
// System.out.println("消息消费成功");
}
}

消费者2
java
public class Customer2 {
public static void main(String[] args) throws IOException, TimeoutException {
// 1.建立连接
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost(Constants.HOST);
connectionFactory.setPort(Constants.PORT);
connectionFactory.setUsername(Constants.USER_NAME);
connectionFactory.setPassword(Constants.PASSWORD);
connectionFactory.setVirtualHost(Constants.VIRTUAL);
Connection connection= connectionFactory.newConnection();
// 2.开启信道
Channel channel=connection.createChannel();
// 创建队列
channel.queueDeclare(Constants.DIRECT_QUEUE_NAME2,true,false,false,null);
// 消费消息
DefaultConsumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("已经接收到消息"+new String(body));
}
};
channel.basicConsume(Constants.DIRECT_QUEUE_NAME2,true,consumer);
// System.out.println("消息消费成功");
}
}

5.Topics(通配符模式)

生产者
java
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException {
// 1.建立连接
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost(Constants.HOST);
connectionFactory.setPort(Constants.PORT);
connectionFactory.setUsername(Constants.USER_NAME);
connectionFactory.setPassword(Constants.PASSWORD);
connectionFactory.setVirtualHost(Constants.VIRTUAL);
Connection connection= connectionFactory.newConnection();
// 2.开启信道
Channel channel=connection.createChannel();
// 申明交换机
channel.exchangeDeclare(Constants.TOPIC_EXCHANGE_NAME, BuiltinExchangeType.TOPIC,true);
// 申明队列
channel.queueDeclare(Constants.TOPIC_QUEUE_NAME1,true,false,false,null);
channel.queueDeclare(Constants.TOPIC_QUEUE_NAME2,true,false,false,null);
// 队列的绑定
channel.queueBind(Constants.TOPIC_QUEUE_NAME1,Constants.TOPIC_EXCHANGE_NAME,"*.a.*");
channel.queueBind(Constants.TOPIC_QUEUE_NAME2,Constants.TOPIC_EXCHANGE_NAME,"*.*.b");
channel.queueBind(Constants.TOPIC_QUEUE_NAME2,Constants.TOPIC_EXCHANGE_NAME,"c.#");
String msg="消息的发送 + direct + ae.a.f ";
String msg1="消息的发送 + direct + c.a.b ";
String msg2="消息的发送 + direct + c.e.f ";
channel.basicPublish(Constants.TOPIC_EXCHANGE_NAME,"ae.a.f",null,msg.getBytes());
channel.basicPublish(Constants.TOPIC_EXCHANGE_NAME,"c.a.b",null,msg1.getBytes());
channel.basicPublish(Constants.TOPIC_EXCHANGE_NAME,"c.e.f",null,msg2.getBytes());
channel.close();
connection.close();
}
}
消费者1
java
public class Customer1 {
public static void main(String[] args) throws IOException, TimeoutException {
// 1.建立连接
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost(Constants.HOST);
connectionFactory.setPort(Constants.PORT);
connectionFactory.setUsername(Constants.USER_NAME);
connectionFactory.setPassword(Constants.PASSWORD);
connectionFactory.setVirtualHost(Constants.VIRTUAL);
Connection connection= connectionFactory.newConnection();
// 2.开启信道
Channel channel=connection.createChannel();
// 3. 申明交换机
channel.exchangeDeclare(Constants.TOPIC_EXCHANGE_NAME, BuiltinExchangeType.TOPIC,true);
// 4.申明队列
channel.queueDeclare(Constants.TOPIC_QUEUE_NAME1,true,false,false,null);
// 5.消费消息
DefaultConsumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费消息+fanout+queue_name1"+new String(body));
}
};
channel.basicConsume(Constants.TOPIC_QUEUE_NAME1,true,consumer);
}
}

消费者2
java
public class Customer2 {
public static void main(String[] args) throws IOException, TimeoutException {
// 1.建立连接
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost(Constants.HOST);
connectionFactory.setPort(Constants.PORT);
connectionFactory.setUsername(Constants.USER_NAME);
connectionFactory.setPassword(Constants.PASSWORD);
connectionFactory.setVirtualHost(Constants.VIRTUAL);
Connection connection= connectionFactory.newConnection();
// 2.开启信道
Channel channel=connection.createChannel();
// 3. 申明交换机
channel.exchangeDeclare(Constants.TOPIC_EXCHANGE_NAME, BuiltinExchangeType.TOPIC,true);
// 4.申明队列
channel.queueDeclare(Constants.TOPIC_QUEUE_NAME2,true,false,false,null);
// 5.消费消息
DefaultConsumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费消息+fanout+queue_name1"+new String(body));
}
};
channel.basicConsume(Constants.TOPIC_QUEUE_NAME2,true,consumer);
}
}

6.RPC通信

生产者
客户端在发送消息之前:
会生成一个唯一的correlationId,用于标记此次请求
创建一个匿名回调队列
发布一条消息到请求队列中,并且进行消息属性的设置
replyTo:回调队列的名字
correlationId:请求Id

创建一个阻塞的队列,用于存储回调结果

接收回调消息
在接受的时候,要先判断返回来的correlationId是否和之前创建队列属性中的correlationId相同

java
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost(Constants.HOST);
connectionFactory.setPort(Constants.PORT);
connectionFactory.setUsername(Constants.USER_NAME);
connectionFactory.setPassword(Constants.PASSWORD);
connectionFactory.setVirtualHost(Constants.VIRTUAL);
Connection connection= connectionFactory.newConnection();
// 2.开启信道
Channel channel=connection.createChannel();
channel.queueDeclare(Constants.RPC_REQUEST_QUEUE,true,false,false,null);
String cotId= UUID.randomUUID().toString();
String msg="rpc通信通信的 消息的发送";
String replyQueueName=channel.queueDeclare().getQueue();
// 消息的发送
AMQP.BasicProperties properties=new AMQP.BasicProperties()
.builder()
.correlationId(cotId)
.replyTo(replyQueueName)
.build();
channel.basicPublish("",Constants.RPC_REQUEST_QUEUE,properties,msg.getBytes(StandardCharsets.UTF_8));
System.out.println("消息发送成功");
// 阻塞队列,用于存储回调的结果
final BlockingQueue<String> response = new ArrayBlockingQueue<>(1);
DefaultConsumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("接收到的消息"+new String(body));
if(cotId.equals(properties.getCorrelationId())){
response.offer(new String(body,"UTF-8"));
}
}
};
// 回调消息的接收
channel.basicConsume(replyQueueName,true,consumer);
// 获得回调的结果
String take = response.take();
System.out.println("[RPC客户端接收]"+take);
channel.close();
connection.close();
}
}
消费者
用于控制每次最多可以同时接收多少消息

java
public class Customer {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost(Constants.HOST);
connectionFactory.setPort(Constants.PORT);
connectionFactory.setUsername(Constants.USER_NAME);
connectionFactory.setPassword(Constants.PASSWORD);
connectionFactory.setVirtualHost(Constants.VIRTUAL);
Connection connection= connectionFactory.newConnection();
// 2.开启信道
Channel channel=connection.createChannel();
channel.queueDeclare(Constants.RPC_RESPONSE_QUEUE,true,false,false,null);
// 接收消息
// 最多只可以接收一个消息
channel.basicQos(1);
System.out.println("Awaiting RPC request");
DefaultConsumer consumer=new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
AMQP.BasicProperties basicProperties=new AMQP.BasicProperties()
.builder()
.correlationId(properties.getCorrelationId())
.build();
System.out.println("消息已经成功的收到");
// 生成返回
String message=new String(body);
String response="request"+message+"response"+"处理成功";
channel.basicPublish("", properties.getReplyTo(),basicProperties,response.getBytes(StandardCharsets.UTF_8));
// 手动对消息进行应答
channel.basicAck(envelope.getDeliveryTag(),false);
}
};
channel.basicConsume(Constants.RPC_REQUEST_QUEUE,false,consumer);
}
}


7.Publisher Confirms(发布确认)

作为消息的中间件,时刻会面临着消息丢失的问题,所以我们需要消息确认机制,来确定消息是否发送成功
消息丢失的情况:
-
网络闪断、Broker 挂了;
-
消息没发送成功;
-
Broker 收到消息但崩溃还没落盘
开启confirm模式
java
channel.confirmSelect();
一旦开启后,RabbitMQ会对每条消息返回一个确认(ACK)或否认(NACK)信号
java
channel.waitForConfirmsOrDie(5000);
等待RabbitMQ对之前的消息进行返回,如果这段时间没有进行返回,就会抛出异常
单独确认
就是一条消息一条消息的进行确认
java
// 单独确认
private static void publishingMessagesIndividually() throws Exception{
try(Connection connection=createConnection()) {
// 创建信道
Channel channel=connection.createChannel();
// 设置信道为confirm模式
channel.confirmSelect();
// 声明信道
channel.queueDeclare(Constants.PUBLISHER_CONFIRMS_QUEUE1,true,false,false,null);
// 发送消息
String msg="单独确认进行消息的发送";
long start=System.currentTimeMillis();
for (int i = 0; i < MESSAGE_COUNT; i++) {
System.out.println("confirms111"+i);
channel.basicPublish("",Constants.PUBLISHER_CONFIRMS_QUEUE1,null,msg.getBytes(StandardCharsets.UTF_8));
channel.waitForConfirmsOrDie(5000);
}
long end=System.currentTimeMillis();
System.out.println("耗时"+(end-start));
}
}
批量确认
当消息到达一定的量时,才对消息进行确认

java
// 批量确认
private static void publishingMessagesInBatches()throws Exception {
try(Connection connection=createConnection()) {
// 创建信道
Channel channel=connection.createChannel();
// 创建信道为confirm模式
channel.confirmSelect();
// 申明队列
channel.queueDeclare(Constants.PUBLISHER_CONFIRMS_QUEUE2,true,false,false,null);
// 发送消息
int batchSize=100;
int outStandingMessageCount=0;
long start=System.currentTimeMillis();
for (int i = 0; i < MESSAGE_COUNT; i++) {
String msg="confirm222"+i;
channel.basicPublish("",Constants.PUBLISHER_CONFIRMS_QUEUE2,null,msg.getBytes());
if(outStandingMessageCount==batchSize){
channel.waitForConfirmsOrDie(5000);
outStandingMessageCount=0;
}
outStandingMessageCount++;
}
if(outStandingMessageCount>0){
channel.waitForConfirmsOrDie(5000);
}
long end=System.currentTimeMillis();
System.out.println("耗时"+(end-start));
}
}
异步确认
用一个线程安全的 SortedSet 来跟踪还未被确认(ack/nack)的消息

注册确定监听器
ConfirmListener是一个接口,用于接收来自RabbitMQ的消息确认回调

java
// 异步确认
private static void handlingPublisherConfirmsAsynchronously()throws Exception {
try(Connection connection=createConnection()) {
Channel channel=connection.createChannel();
// 创建信道模式为confirm
channel.confirmSelect();
channel.queueDeclare(Constants.PUBLISHER_CONFIRMS_QUEUE3,true,false,false,null);
long start=System.currentTimeMillis();
SortedSet<Object> confirm = Collections.synchronizedSortedSet(new TreeSet<>());
channel.addConfirmListener(new ConfirmListener() {
@Override
public void handleAck(long deliverTag, boolean multiple) throws IOException {
if(multiple){
confirm.headSet(deliverTag+1).clear();
}else{
confirm.remove(deliverTag);
}
}
@Override
public void handleNack(long deliverTag, boolean multiple) throws IOException {
if(multiple){
confirm.headSet(deliverTag+1).clear();
}else{
confirm.remove(deliverTag);
}
}
});
// 发送消息
for (int i = 0; i < MESSAGE_COUNT; i++) {
String msg="confirm333"+i;
long seqNo=channel.getNextPublishSeqNo();
channel.basicPublish("",Constants.PUBLISHER_CONFIRMS_QUEUE3,null,msg.getBytes());
confirm.add(seqNo);
}
while (!confirm.isEmpty()){
Thread.sleep(10);
}
long end=System.currentTimeMillis();
System.out.println("耗时"+(end-start));
}
}
所有的消息确认的代码
java
public class PublishConfirm {
private static final Integer MESSAGE_COUNT=1000;
static Connection createConnection() throws IOException, TimeoutException {
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost(Constants.HOST);
connectionFactory.setPort(Constants.PORT);
connectionFactory.setUsername(Constants.USER_NAME);
connectionFactory.setPassword(Constants.PASSWORD);
connectionFactory.setVirtualHost(Constants.VIRTUAL);
return connectionFactory.newConnection();
}
public static void main(String[] args) throws Exception {
// 单独确认
publishingMessagesIndividually();
// 批量确认
publishingMessagesInBatches();
// 异步确认
handlingPublisherConfirmsAsynchronously();
}
// 异步确认
private static void handlingPublisherConfirmsAsynchronously()throws Exception {
try(Connection connection=createConnection()) {
Channel channel=connection.createChannel();
// 创建信道模式为confirm
channel.confirmSelect();
channel.queueDeclare(Constants.PUBLISHER_CONFIRMS_QUEUE3,true,false,false,null);
long start=System.currentTimeMillis();
SortedSet<Object> confirm = Collections.synchronizedSortedSet(new TreeSet<>());
channel.addConfirmListener(new ConfirmListener() {
@Override
public void handleAck(long deliverTag, boolean multiple) throws IOException {
if(multiple){
confirm.headSet(deliverTag+1).clear();
}else{
confirm.remove(deliverTag);
}
}
@Override
public void handleNack(long deliverTag, boolean multiple) throws IOException {
if(multiple){
confirm.headSet(deliverTag+1).clear();
}else{
confirm.remove(deliverTag);
}
}
});
// 发送消息
for (int i = 0; i < MESSAGE_COUNT; i++) {
String msg="confirm333"+i;
long seqNo=channel.getNextPublishSeqNo();
channel.basicPublish("",Constants.PUBLISHER_CONFIRMS_QUEUE3,null,msg.getBytes());
confirm.add(seqNo);
}
while (!confirm.isEmpty()){
Thread.sleep(10);
}
long end=System.currentTimeMillis();
System.out.println("耗时"+(end-start));
}
}
// 批量确认
private static void publishingMessagesInBatches()throws Exception {
try(Connection connection=createConnection()) {
// 创建信道
Channel channel=connection.createChannel();
// 创建信道为confirm模式
channel.confirmSelect();
// 申明队列
channel.queueDeclare(Constants.PUBLISHER_CONFIRMS_QUEUE2,true,false,false,null);
// 发送消息
int batchSize=100;
int outStandingMessageCount=0;
long start=System.currentTimeMillis();
for (int i = 0; i < MESSAGE_COUNT; i++) {
String msg="confirm222"+i;
channel.basicPublish("",Constants.PUBLISHER_CONFIRMS_QUEUE2,null,msg.getBytes());
if(outStandingMessageCount==batchSize){
channel.waitForConfirmsOrDie(5000);
outStandingMessageCount=0;
}
outStandingMessageCount++;
}
if(outStandingMessageCount>0){
channel.waitForConfirmsOrDie(5000);
}
long end=System.currentTimeMillis();
System.out.println("耗时"+(end-start));
}
}
// 单独确认
private static void publishingMessagesIndividually() throws Exception{
try(Connection connection=createConnection()) {
// 创建信道
Channel channel=connection.createChannel();
// 设置信道为confirm模式
channel.confirmSelect();
// 声明信道
channel.queueDeclare(Constants.PUBLISHER_CONFIRMS_QUEUE1,true,false,false,null);
// 发送消息
String msg="单独确认进行消息的发送";
long start=System.currentTimeMillis();
for (int i = 0; i < MESSAGE_COUNT; i++) {
System.out.println("confirms111"+i);
channel.basicPublish("",Constants.PUBLISHER_CONFIRMS_QUEUE1,null,msg.getBytes(StandardCharsets.UTF_8));
channel.waitForConfirmsOrDie(5000);
}
long end=System.currentTimeMillis();
System.out.println("耗时"+(end-start));
}
}
}