系列文章:
第二个环节就是消息从交换机路由到队列。在什么情况下,消息会无法路由到正确的队列?可能因为路由键错误,或者队列不存在。有两种方式处理无法路由的消息:
- 一种就是让服务端回发给生产者
- 一种是让交换机路由到另一个备份的交换机
1.消息回发
消息回发的方式:使用 mandatory 参数和 ReturnListener
public class ReturnListenerProducer {
public static void main(String[] args) throws Exception{
ConnectionFactory factory = new ConnectionFactory();
factory.setUri(ResourceUtil.getKey("rabbitmq.uri"));
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
// 添加监听
channel.addReturnListener(new ReturnListener() {
public void handleReturn(int replyCode,
String replyText,
String exchange,
String routingKey,
AMQP.BasicProperties properties,
byte[] body)
throws IOException {
System.out.println("=========监听器收到了无法路由,被返回的消息============");
System.out.println("replyText:"+replyText);
System.out.println("exchange:"+exchange);
System.out.println("routingKey:"+routingKey);
System.out.println("message:"+new String(body));
}
});
AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder().deliveryMode(2).
contentEncoding("UTF-8").build();
// 发送到了默认的交换机上,由于没有任何队列使用这个关键字跟交换机绑定,所以会被退回
// 第三个参数是设置的mandatory,如果mandatory是false,消息也会被直接丢弃
channel.basicPublish("","mydirect",true, properties,"只为更好的你".getBytes());
TimeUnit.SECONDS.sleep(10);
channel.close();
connection.close();
}
}
在SpringAMQP中是ReturnCallback
// 构建RabbitTemplate的Bean时配置
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMandatory(true);
// 当消息成功到达exchange,且无法被路由时触发回调,进行消息回发
rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback(){
public void returnedMessage(Message message,
int replyCode,
String replyText,
String exchange,
String routingKey){
System.out.println("回发的消息:");
System.out.println("replyCode: "+replyCode);
System.out.println("replyText: "+replyText);
System.out.println("exchange: "+exchange);
System.out.println("routingKey: "+routingKey);
}
});
return rabbitTemplate;
}
2.进入备份交换机
消息路由到备份交换机的方式:在创建交换机的时候,从属性中指定备份交换机。
Map<String,Object> arguments = new HashMap<String,Object>();
arguments.put("alternate-exchange","ALTERNATE_EXCHANGE");// 指定交换机的备份交换机
channel.exchangeDeclare("TEST_EXCHANGE","topic",false,false,false,arguments); // 声明交换机
注:备份交换机是对于在消息路由处失败,还没有进入消息队列的消息,而死信是已经入队,但过期或投递失败的