RabbitMQ对AMQP规范的一个扩展。被投递消息被拒绝后的一个可选行为,往往用在对问题消息的诊断上。
消息变成死信一般是以下几种情况:
- 消息被拒绝,并且设置 requeue 参数为 false
- 消息过期
- 队列达到最大长度
死信交换器仍然只是一个普通的交换器,创建时并没有特别要求和操作。在创建队列的时候,声明该交换器将用作保存被拒绝的消息即可,相关的参数是x-dead-letter-exchange。
和备用交换器的区别
1、备用交换器是主交换器无法路由消息,那么消息将被路由到这个新的备用交换器,而死信交换器则是接收过期或者被拒绝的消息。
2、备用交换器是在声明主交换器时发生联系,而死信交换器则声明队列时发生联系。
普通的消费者,消费死信队列dlx_accept
/**
*类说明:普通的消费者,消费死信队列dlx_accept
*/
public class DlxProcessConsumer {
public final static String DLX_EXCHANGE_NAME = "dlx_accept";
public static void main(String[] argv)
throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
// 打开连接和创建频道,与发送端一样
Connection connection = factory.newConnection();
final Channel channel = connection.createChannel();
channel.exchangeDeclare(DLX_EXCHANGE_NAME,
BuiltinExchangeType.TOPIC);
/*声明一个队列*/
String queueName = "dlx_accept";
channel.queueDeclare(queueName,false,false,
false,null);
/*绑定,将队列和交换器通过路由键进行绑定*/
channel.queueBind(queueName,
DLX_EXCHANGE_NAME,"#");
System.out.println("waiting for message........");
/*声明了一个死信消费者*/
final Consumer consumer = 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.out.println("Received dead letter["
+envelope.getRoutingKey()
+"]"+message);
}
};
/*消费者正式开始在指定队列上消费消息*/
channel.basicConsume(queueName,true,consumer);
}
}
普通的消费者,消费死信队列dlx_warn_accept,路由键为dlx_other
/**
*类说明:普通的消费者,消费死信队列dlx_warn_accept,路由键为dlx_other
*/
public class DlxProcessOtherConsumer {
public static void main(String[] argv)
throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
// 打开连接和创建频道,与发送端一样
Connection connection = factory.newConnection();
final Channel channel = connection.createChannel();
channel.exchangeDeclare(DlxProcessWarnConsumer.DLX_EXCHANGE_NAME,
BuiltinExchangeType.TOPIC);
/*声明一个队列*/
String queueName = "dlx_other";
channel.queueDeclare(queueName,false,false,
false,null);
/*绑定,将队列和交换器通过路由键进行绑定*/
channel.queueBind(queueName,
DlxProcessWarnConsumer.DLX_EXCHANGE_NAME,
"dlx_other");
System.out.println("waiting for message........");
/*声明了一个死信消费者*/
final Consumer consumer = 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.out.println("Received dead letter["
+envelope.getRoutingKey()
+"]"+message);
}
};
/*消费者正式开始在指定队列上消费消息*/
channel.basicConsume(queueName,true,consumer);
}
}
普通的消费者,消费死信队列dlx_warn_accept,路由键为dlx_warn
/**
*类说明:普通的消费者,消费死信队列dlx_warn_accept,路由键为dlx_warn
*/
public class DlxProcessWarnConsumer {
public final static String DLX_EXCHANGE_NAME = "dlx_warn_accept";
public final static String DLX_ROUTE_KEY = "dlx_warn";
public static void main(String[] argv)
throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
// 打开连接和创建频道,与发送端一样
Connection connection = factory.newConnection();
final Channel channel = connection.createChannel();
channel.exchangeDeclare(DLX_EXCHANGE_NAME,
BuiltinExchangeType.TOPIC);
/*声明一个队列*/
String queueName = "dlx_warn_accept";
channel.queueDeclare(queueName,false,false,
false,null);
/*绑定,将队列和交换器通过路由键进行绑定*/
channel.queueBind(queueName,
DLX_EXCHANGE_NAME,DLX_ROUTE_KEY);
System.out.println("waiting for message........");
/*声明了一个死信消费者*/
final Consumer consumer = 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.out.println("Received dead letter["
+envelope.getRoutingKey()
+"]"+message);
}
};
/*消费者正式开始在指定队列上消费消息*/
channel.basicConsume(queueName,true,consumer);
}
}
普通的消费者,但是自己无法消费的消息,将投入死信队列
/**
*类说明:普通的消费者,但是自己无法消费的消息,将投入死信队列
*/
public class WillMakeDlxConsumer {
public static void main(String[] argv)
throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
// 打开连接和创建频道,与发送端一样
Connection connection = factory.newConnection();
final Channel channel = connection.createChannel();
channel.exchangeDeclare(DlxProducer.EXCHANGE_NAME,
BuiltinExchangeType.TOPIC);
/*声明一个队列,并绑定死信交换器*/
String queueName = "dlx_make";
Map<String,Object> args = new HashMap<String,Object>();
args.put("x-dead-letter-exchange",
DlxProcessConsumer.DLX_EXCHANGE_NAME);
channel.queueDeclare(queueName,false,true,
false,
args);
/*绑定,将队列和交换器通过路由键进行绑定*/
channel.queueBind(queueName,
DlxProducer.EXCHANGE_NAME,"#");
System.out.println("waiting for message........");
/*声明了一个消费者*/
final Consumer consumer = 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");
if(envelope.getRoutingKey().equals("error")){
System.out.println("Received["
+envelope.getRoutingKey()
+"]"+message);
channel.basicAck(envelope.getDeliveryTag(),
false);
}else{
System.out.println("Will reject["
+envelope.getRoutingKey()
+"]"+message);
channel.basicReject(envelope.getDeliveryTag(),
false);
}
}
};
/*消费者正式开始在指定队列上消费消息*/
channel.basicConsume(queueName,false,consumer);
}
}
普通的消费者,但是自己无法消费的消息,通过路由键将投入死信队列
/**
*类说明:普通的消费者,但是自己无法消费的消息,通过路由键将投入死信队列
*/
public class WillMakeWarnDlxConsumer {
public static void main(String[] argv)
throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
// 打开连接和创建频道,与发送端一样
Connection connection = factory.newConnection();
final Channel channel = connection.createChannel();
channel.exchangeDeclare(DlxProducer.EXCHANGE_NAME,
BuiltinExchangeType.TOPIC);
/*声明一个队列,并绑定死信交换器*/
String queueName = "dlx_warn_make";
Map<String, Object> arguments = new HashMap<String, Object>();
//死信交换器
arguments.put("x-dead-letter-exchange",
DlxProcessWarnConsumer.DLX_EXCHANGE_NAME);
//死信路由键,会替换消息原来的路由键
arguments.put("x-dead-letter-routing-key",
DlxProcessWarnConsumer.DLX_ROUTE_KEY);
channel.queueDeclare(queueName,false,false,
false,arguments);
/*绑定,将队列和交换器通过路由键进行绑定*/
channel.queueBind(queueName,
DlxProducer.EXCHANGE_NAME,"#");
System.out.println("waiting for message........");
/*声明了一个消费者*/
final Consumer consumer = 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");
if(envelope.getRoutingKey().equals("error")){
System.out.println("Received["
+envelope.getRoutingKey()
+"]"+message);
channel.basicAck(envelope.getDeliveryTag(),
false);
}else{
System.out.println("Will reject["
+envelope.getRoutingKey()
+"]"+message);
channel.basicReject(envelope.getDeliveryTag(),
false);
}
}
};
/*消费者正式开始在指定队列上消费消息*/
channel.basicConsume(queueName,false,consumer);
}
}
生产者:
public class DlxProducer {
public final static String EXCHANGE_NAME = "dlx_make";
public static void main(String[] args) throws IOException, TimeoutException {
/**
* 创建连接连接到MabbitMQ
*/
ConnectionFactory factory = new ConnectionFactory();
// 设置MabbitMQ所在主机ip或者主机名
factory.setHost("127.0.0.1");
// 创建一个连接
Connection connection = factory.newConnection();
// 创建一个信道
Channel channel = connection.createChannel();
// 指定转发
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
/*日志消息级别,作为路由键使用*/
String[] serverities = {"error","info","warning"};
for(int i=0;i<3;i++){
String severity = serverities[i%3];
String msg = "Hellol,RabbitMq"+(i+1);
/*发布消息,需要参数:交换器,路由键,其中以日志消息级别为路由键*/
channel.basicPublish(EXCHANGE_NAME,severity,null,
msg.getBytes());
System.out.println("Sent "+severity+":"+msg);
}
// 关闭频道和连接
channel.close();
connection.close();
}
}
运行结果: