//生产者
//省略 创建连接和channel
//打开消息确认模式
channel.confirmSelect();
String exchange = "test.confirm.exchange";
String routingKey = "confirm.routing-key";
String message = "hello rabbitmq";
channel.basicPublish(exchange, routingKey, null, message.getBytes());
//添加确认监听
channel.addConfirmListener(new ConfirmListener() {
//消息成功发送回调
public void handleAck(long deliverTag, boolean multiple) throws IOException {
System.err.println("----发送成功---");
}
//消息发送失败回调
public void handleNack(long deliverTag, boolean multiple) throws IOException {
//队列满、磁盘满 等等情况
System.err.println("----发送失败---");
}
});
//消费者
//省略 创建连接和channel
String queueName = "confirm-queue";
String exchange = "test.confirm.exchange";
String routingKey = "confirm.#";
//声明交换机
channel.exchangeDeclare(exchange, "topic");
//声明队列
channel.queueDeclare(queueName, false, false, false, null);
//队列、交换机、routing key 三者绑定
channel.queueBind(queueName, exchange, routingKey);
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.err.println(message);
}
};
channel.basicConsume(queueName, true, defaultConsumer);
}
Mandatory: 如果为true,则监听器会收到路由不可达的消息,然后进行处理,如果为false,Broker会自动删除消息。
//生产者
//省略 创建连接和channel
String exchange = "test.return.exchange";
String routingKey = "return.routing-key";
String message = "hello rabbitmq";
//声明交换机 不绑定队列 触发return 回调
channel.exchangeDeclare(exchange, "topic");
//添加 return 监听器
channel.addReturnListener(new ReturnListener() {
public void handleReturn(int replyCode, String replyTest, String exchange, String routingKey,
AMQP.BasicProperties basicProperties, byte[] body) throws IOException {
System.err.println("replyCode: " + replyCode);
System.err.println("replyTest: " + replyTest);
System.err.println("exchange: " + exchange);
System.err.println("routingKey: " + routingKey);
System.err.println("basicProperties: " + basicProperties);
System.err.println("body: " + new String(body, "UTF-8"));
}
});
//第三个参数 是否打开 return 机制
channel.basicPublish(exchange, routingKey, true,null, message.getBytes());
}
什么是消费端限流?
void BasicQos(int prefetchSize,short prefetchCount,boolean global);
prefetchSize:消息的大小限制,0 不限制。
prefetchCount:推送的消息数目。
global:true\false 是否将以上设置 应用于channel上
简单点说:就是上面限制是channel级别还是consumer级别
//生产者
//省略 创建连接和channel
String exchange = "test.qos.exchange";
String routingKey = "qos.routing-key";
String message = "hello rabbitmq";
for (int i = 0; i < 9; i++) {
channel.basicPublish(exchange, routingKey, null, message.getBytes());
}
channel.close();
connection.close();
//消费者
//省略 创建连接和channel
String queueName = "qos-queue";
String exchange = "test.qos.exchange";
String routingKey = "qos.routing-key";
//声明交换机
channel.exchangeDeclare(exchange, "topic");
//声明队列
channel.queueDeclare(queueName, false, false, false, null);
//队列、交换机、routing key 三者绑定
channel.queueBind(queueName, exchange, routingKey);
// 限流 第一件事:autoAck 设置为false
channel.basicQos(0, 3, false);
channel.basicConsume(queueName, false, new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.err.println(message);
//第二个参数 是否批量签收
channel.basicAck(envelope.getDeliveryTag(), true);
}
});
ACK:签收,NACK不签收
//生产者
//省略 创建连接和channel
String exchange = "test.ack.exchange";
String routingKey = "ack.routing-key";
for (int i = 0; i < 5; i++) {
Map<String, Object> headers = new HashMap<>();
headers.put("index", i);
AMQP.BasicProperties properties = new AMQP.BasicProperties().builder()
.deliveryMode(2) //持久化
.headers(headers)
.build();
String message = "hello rabbitmq " + i;
channel.basicPublish(exchange, routingKey, properties, message.getBytes());
}
//消费者
//省略 创建连接和channel
String queueName = "ack-queue";
String exchange = "test.ack.exchange";
String routingKey = "ack.routing-key";
//声明交换机
channel.exchangeDeclare(exchange, "topic");
//声明队列
channel.queueDeclare(queueName, false, false, false, null);
//队列、交换机、routing key 三者绑定
channel.queueBind(queueName, exchange, routingKey);
//必须手工签收 关闭autoACK
channel.basicConsume(queueName, false, new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.err.println(message);
if ((Integer) properties.getHeaders().get("index") == 0) {
//第三个参数 是否重回队列
channel.basicNack(envelope.getDeliveryTag(), false, true);
}else{
//第二个参数 是否批量签收
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
});
消息变成死信有以下几种情况
- 消息被拒绝(basic.reject/basic.nack)并且requeue = false。
- 消息TTL过期
- 队列达到最大长度
例如:
Exchange:dlx.exchange
Queue:dlx.queue
Routing key:#
//生产者
//省略 创建连接和channel
String exchange = "test.dlx.exchange";
String routingKey = "dlx.routing-key";
//进行私信队列的声明
channel.exchangeDeclare("dlx.exchange", "topic", true, false, false, null);
channel.queueDeclare("dlx.queue", false, false, false, null);
channel.queueBind("dlx.queue", "dlx.exchange", "#");
//声明普通队列和交换机
String queueName = "test.dlx-queue";
channel.exchangeDeclare(exchange, "topic");
//-----------------------设置队列的私信队列---------------------------------------
Map<String, Object> arguments = new HashMap<>();
arguments.put("x-dead-letter-exchange", "dlx.exchange");
//这个arguments属性要设置到声明队列上
channel.queueDeclare(queueName, false, false, false, arguments);
//-----------------------设置队列的私信队列---------------------------------------
channel.queueBind(queueName, exchange, routingKey);
AMQP.BasicProperties properties = new AMQP.BasicProperties().builder()
.expiration("1000") //设置过期时间 不启动消费者 使消息变为私信
.build();
String message = "hello rabbitmq";
channel.basicPublish(exchange, routingKey,properties, message.getBytes());
channel.close();
connection.close();