Java初识RabbitMQ一消息确认机制
生产端消息确认机制
消息确认,是指生产端投递消息后,如果Broker
收到消息,则会给我们生产端一个应答。生产端接收应答,用来确定这条消息是否正常发送到Broker
,这种方式也是消息可靠性投递的核心保障!
消息确认机制流程图
如何实现消息确认机制?
我们需要实现消息确认机制,首先我们必须要开启这种机制。
// 开启消息确认机制
channel.confirmSelect();
confirmSelect()
源码如下:
/**
* Enables publisher acknowledgements on this channel.
* @see com.rabbitmq.client.AMQP.Confirm.Select
* @throws java.io.IOException if an error is encountered
*/
Confirm.SelectOk confirmSelect() throws IOException;
Enables publisher acknowledgements on this channel.
从注释中也可以知道,通过Channel
调用这个方法会开启生产端消息确认机制。
现在我们开启了生产端消息确认机制,但当Broker
收到消息,给我们生产端一个应答,我们需要有处理这个应答的方法(异步回调方法处理消息发送成功或者失败,这很像博主之前用AIO模型实现的简易多人聊天室,也是异步回调),所以需要一个处理应答的回调函数,根据具体的结果对消息进行重新发送、或记录日志等后续处理,如下:
// 添加消息确认监听(异步回调)
channel.addConfirmListener(new ConfirmListener() {
@Override
public void handleAck(long deliveryTag, boolean multiple) throws IOException {
System.out.println("------------ack---------------");
}
@Override
public void handleNack(long deliveryTag, boolean multiple) throws IOException {
System.out.println("------------no ack---------------");
}
});
现在我们实现了消息确认机制,生产端投递消息,Broker
收到消息,给生产端一个应答,如果消息成功收到,回调函数会输出ack
,否则输出no ack
。
生产端
我们这里使用的是默认交换机,它的路由规则可以看看下面这篇博客。
Java初识RabbitMQ一交换机(default exchange)
package com.kaven.rabbitmq.api.confirm;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConfirmListener;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Producer {
// 自己服务器的IP
private static String ip = "IP";
// RabbitMQ启动的默认端口,也是应用程序进行连接RabbitMQ的端口
private static int port = 5672;
// RabbitMQ有一个 "/" 的虚拟主机
private static String virtualHost = "/";
// default exchange
private static String exchange = "";
// default exchange 的路由规则: routingKey(test) 将匹配同名的 queue(test)
private static String routingKey = "test";
public static void main(String[] args) throws IOException, TimeoutException {
// 1 创建ConnectionFactory
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost(ip);
connectionFactory.setPort(port);
connectionFactory.setVirtualHost(virtualHost);
// 2 创建Connection
Connection connection = connectionFactory.newConnection();
// 3 创建Channel
Channel channel = connection.createChannel();
// 4 开启消息确认机制
channel.confirmSelect();
// 5 发送消息
for (int i = 0; i < 10; i++) {
String msg = "消息确认模式:RabbitMQ send confirm message "+i;
channel.basicPublish(exchange , routingKey , null , msg.getBytes());
}
// 6 添加消息确认监听(异步回调)
channel.addConfirmListener(new ConfirmListener() {
@Override
public void handleAck(long deliveryTag, boolean multiple) throws IOException {
System.out.println("------------ack---------------");
}
@Override
public void handleNack(long deliveryTag, boolean multiple) throws IOException {
System.out.println("------------no ack---------------");
}
});
}
}
消费端
package com.kaven.rabbitmq.api.confirm;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer {
// 自己服务器的IP
private static String ip = "IP";
// RabbitMQ启动的默认端口,也是应用程序进行连接RabbitMQ的端口
private static int port = 5672;
// RabbitMQ有一个 "/" 的虚拟主机
private static String virtualHost = "/";
// default exchange
private static String exchange = "";
// 队列名
private static String queueName = "test";
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
// 1 创建ConnectionFactory
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost(ip);
connectionFactory.setPort(port);
connectionFactory.setVirtualHost(virtualHost);
// 2 创建Connection
Connection connection = connectionFactory.newConnection();
// 3 创建Channel
Channel channel = connection.createChannel();
// 4 创建Queue
channel.queueDeclare(queueName , true , false , false , null);
// 5 创建消费者
QueueingConsumer consumer = new QueueingConsumer(channel);
channel.basicConsume(queueName , true , consumer);
// 6 接收消息
while (true){
QueueingConsumer.Delivery delivery = consumer.nextDelivery();
String msg = new String(delivery.getBody());
System.out.println(msg);
}
}
}
测试
运行生产端会发现每次运行结果都可能不一样,会有多种情况出现,因为Broker
会进行优化,有时会批量一次性Confirm ,有时会分开几条Confirm。
五条。
------------ack---------------
------------ack---------------
------------ack---------------
------------ack---------------
------------ack---------------
三条。
------------ack---------------
------------ack---------------
------------ack---------------
还有其他情况就不列举了。
我们来看看RabbitMQ Management
,有40
条消息准备好了,因为我启动了四次生产端来进行测试。
现在,我们启动消费端,消费端也成功收到了这40
条消息。
消息确认模式:RabbitMQ send confirm message 0
消息确认模式:RabbitMQ send confirm message 1
消息确认模式:RabbitMQ send confirm message 2
消息确认模式:RabbitMQ send confirm message 3
消息确认模式:RabbitMQ send confirm message 4
消息确认模式:RabbitMQ send confirm message 5
消息确认模式:RabbitMQ send confirm message 6
消息确认模式:RabbitMQ send confirm message 7
消息确认模式:RabbitMQ send confirm message 8
消息确认模式:RabbitMQ send confirm message 9
消息确认模式:RabbitMQ send confirm message 0
消息确认模式:RabbitMQ send confirm message 1
消息确认模式:RabbitMQ send confirm message 2
消息确认模式:RabbitMQ send confirm message 3
消息确认模式:RabbitMQ send confirm message 4
消息确认模式:RabbitMQ send confirm message 5
消息确认模式:RabbitMQ send confirm message 6
消息确认模式:RabbitMQ send confirm message 7
消息确认模式:RabbitMQ send confirm message 8
消息确认模式:RabbitMQ send confirm message 9
消息确认模式:RabbitMQ send confirm message 0
消息确认模式:RabbitMQ send confirm message 1
消息确认模式:RabbitMQ send confirm message 2
消息确认模式:RabbitMQ send confirm message 3
消息确认模式:RabbitMQ send confirm message 4
消息确认模式:RabbitMQ send confirm message 5
消息确认模式:RabbitMQ send confirm message 6
消息确认模式:RabbitMQ send confirm message 7
消息确认模式:RabbitMQ send confirm message 8
消息确认模式:RabbitMQ send confirm message 9
消息确认模式:RabbitMQ send confirm message 0
消息确认模式:RabbitMQ send confirm message 1
消息确认模式:RabbitMQ send confirm message 2
消息确认模式:RabbitMQ send confirm message 3
消息确认模式:RabbitMQ send confirm message 4
消息确认模式:RabbitMQ send confirm message 5
消息确认模式:RabbitMQ send confirm message 6
消息确认模式:RabbitMQ send confirm message 7
消息确认模式:RabbitMQ send confirm message 8
消息确认模式:RabbitMQ send confirm message 9
我们再来看看RabbitMQ Management
,很显然消息已经全部被消费者接收了。