2019独角兽企业重金招聘Python工程师标准>>>
rabbitmq客户端发送消息的方法为basicPublish 这个方法有很多重载的方法。其中有一个方法,里面有一个参数mandatory。当mandatory 参数设为 true 时,交换器无法根据自身的类型和路由键找到一个符合条件的队列,那么 RabbitMq会调用 Basic.Return命令将消息返回给生产者。当mandatory
数设置为 false 时,出现上述情形,则消息直接被丢弃。
/**
* Publish a message.
*
* Invocations of Channel#basicPublish
will eventually block if a
* resource-driven alarm is in effect.
*
* @see com.rabbitmq.client.AMQP.Basic.Publish
* @see Resource-driven alarms
* @param exchange the exchange to publish the message to
* @param routingKey the routing key
* @param mandatory true if the 'mandatory' flag is to be set
* @param props other properties for the message - routing headers etc
* @param body the message body
* @throws java.io.IOException if an error is encountered
*/
void basicPublish(String exchange, String routingKey, boolean mandatory, BasicProperties props, byte[] body)
throws IOException;
简单来说,mandatory 为true时,发送消息到交换机,交换机无法路由该消息,那么发送端可以可以监听到rabbitmq的告知“这条消息无法路由”。
声明交换机、队列 并进行绑定
/**
* 1、声明交换机
*/
@Test
public void decalreExchange() throws Exception {
String exchange = "hello_mandatory";
// 获取到连接
Connection connection = ConnectionUtil.getConnection();
// 获取通道
Channel channel = connection.createChannel();
// 声明exchange,指定类型为direct
channel.exchangeDeclare(exchange, BuiltinExchangeType.DIRECT,true,false,false,new HashMap<>());
}
/**
* 2、声明队列并绑定到交换机
*/
@Test
public void decalreQueueAndBind() throws Exception {
String exchange = "hello_mandatory";
// 获取到连接
Connection connection = ConnectionUtil.getConnection();
// 获取通道
Channel channel = connection.createChannel();
String queueName = "hello_mandatory_c";
// 声明队列
channel.queueDeclare(queueName, false, false, false, null);
// 绑定队列到交换机
channel.queueBind(queueName, exchange, "aaa");
}
可以看到队列hello_mandatory_c 绑定到了交换机,routing key 为 aaa
发送消息
/**
* 生产者发送消息
* @throws Exception
*/
@Test
public void sendMessage() throws Exception {
String exchange = "hello_mandatory";
// 获取到连接
Connection connection = ConnectionUtil.getConnection();
// 获取通道
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 {
String message = new String(body);
log.info("replyText:{}",replyText);
log.info("exchange:{}",exchange);
log.info("routingKey:{}",routingKey);
log.info("message:{}",message);
}
});
String message = "less is more";
// 发布消息到Exchange 设置mandatory为true
channel.basicPublish(exchange, "bbb", true, null, message.getBytes());
// 发布消息到Exchange 设置mandatory为true
channel.basicPublish(exchange, "aaa", true, null, message.getBytes());
log.debug("Producer send message:{}", message);
TimeUnit.SECONDS.sleep(10);
channel.close();
connection.close();
}
可以看到bbb 无法路由 ,rabbitmq返回消息给客户端
路由键为aaa的消息成功的发送到了队列hello_mandatory_c
获取消息,可以看到“less is more”
备用交换器
生产者在发送消息的时候如果不设置 mandatory 参数那么消息在未被路由的情况下将会丢失,如果设置了 mandatory 参数,那么需要添加 ReturnListener 的编程逻辑,生产者的代码将变得复杂。如果既不想复杂化生产者的编程逻辑,又不想消息丢失,那么可以使用备用交换器,这样可以将未被路由的消息存储在RabbitMQ 中,在需要的时候去处理这些消息。
声明交换机
/**
* 1、声明交换机
*/
@Test
public void decalreExchange() throws Exception {
String mainExchange = "hello_back_me";
String backExchange = "hello_back_be";
// 获取到连接
Connection connection = ConnectionUtil.getConnection();
// 获取通道
Channel channel = connection.createChannel();
//设置备用交换机
Map argsMap = new HashMap();
argsMap.put("alternate-exchange", backExchange);
// 声明exchange,指定类型为direct
channel.exchangeDeclare(mainExchange, BuiltinExchangeType.DIRECT, true, false, false, argsMap);
// 声明exchange,指定类型为fanout
channel.exchangeDeclare(backExchange, BuiltinExchangeType.FANOUT, true, false, false, new HashMap<>());
}
可以看到交换机 hello_back_me 中多了一个参数
声明队列并绑定到交换机
/**
* 2、声明队列并绑定到交换机
*/
@Test
public void decalreQueueAndBind() throws Exception {
String mainExchange = "hello_back_me";
String backExchange = "hello_back_be";
// 获取到连接
Connection connection = ConnectionUtil.getConnection();
// 获取通道
Channel channel = connection.createChannel();
String queueName = "hello_back_me_c";
// 声明队列
channel.queueDeclare(queueName, false, false, false, null);
// 绑定队列到交换机
channel.queueBind(queueName, mainExchange, "aaa");
// 声明一个队列
String queueNameBack = "hello_back_be_c";
// 声明队列
channel.queueDeclare(queueNameBack, false, false, false, null);
// 绑定队列到交换机
channel.queueBind(queueNameBack, backExchange, "");
}
发送消息
/**
* 生产者发送消息
*
* @throws Exception
*/
@Test
public void sendMessage() throws Exception {
String exchange = "hello_back_me";
// 获取到连接
Connection connection = ConnectionUtil.getConnection();
// 获取通道
Channel channel = connection.createChannel();
// 发布消息到Exchange 设置mandatory为false
channel.basicPublish(exchange, "bbb", false, null, "less is more bbb".getBytes());
// 发布消息到Exchange 设置mandatory为false
channel.basicPublish(exchange, "aaa", false, null, "less is more aaa".getBytes());
log.debug("Producer send success");
TimeUnit.SECONDS.sleep(10);
channel.close();
connection.close();
}
运行后可以看到,bbb无法路由的消息进入了hello_back_be_c
详细源码地址
https://github.com/suzhe2018/rabbitmq-item