RabbitMQ服务器会根据路由键将消息从交换器路由到队列中,如何处理投递到多个队列的情况?这里不同类型的交换器起到了重要的作用。
最常用的交换机有三种:direct、topic、fanout。我分别叫他们:“直接连接交换机”,“主题路由匹配交换机”,“无路由交换机”
fanout类型的Exchange路由规则非常简单,它会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中。
上图中,生产者(P)发送到Exchange(X)的所有消息都会路由到图中的两个Queue,并最终被两个消费者(C1与C2)消费。
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = QueueName, durable = "true", ignoreDeclarationExceptions = "true"),
exchange = @Exchange(value = EventConfig.exchangeGR, type = ExchangeTypes.FANOUT, durable = "true"),
ignoreDeclarationExceptions = "true"))
public void saveReapirTestee(@Payload Event event, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag){
try {
service.saveInventory(Event,0001L, "系统消息实时生成");
log.info("save maintain receive inventory succeed");
channel.basicAck(deliveryTag, false);
}catch (Exception e){
log.info("save receive inventory failed !");
log.info("save receive inventory json -->"+JSONObject.toJSONString(goodsReciptEvent));
try {
channel.basicAck(deliveryTag, false);
}catch (Exception ee){
log.error("save receive inventory failed !",e);
}
}
}
direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routing key完全匹配的Queue中。
以上图的配置为例,我们以routingKey=”error”发送消息到Exchange,则消息会路由到Queue1(amqp.gen-S9b…,这是由RabbitMQ自动生成的Queue名称)和Queue2(amqp.gen-Agl…);如果我们以routingKey=”info”或routingKey=”warning”来发送消息,则消息只会路由到Queue2。如果我们以其他routingKey发送消息,则消息不会路由到这两个Queue中。
前面讲到direct类型的Exchange路由规则是完全匹配binding key与routing key,但这种严格的匹配方式在很多情况下不能满足实际业务需求。topic类型的Exchange在匹配规则上进行了扩展,它与direct类型的Exchage相似,也是将消息路由到binding key与routing key相匹配的Queue中,但这里的匹配规则有些不同,它约定:
以上图中的配置为例,routingKey=”quick.orange.rabbit”的消息会同时路由到Q1与Q2,routingKey=”lazy.orange.fox”的消息会路由到Q1与Q2,routingKey=”lazy.brown.fox”的消息会路由到Q2,routingKey=”lazy.pink.rabbit”的消息会路由到Q2(只会投递给Q2一次,虽然这个routingKey与Q2的两个bindingKey都匹配);routingKey=”quick.brown.fox”、routingKey=”orange”、routingKey=”quick.orange.male.rabbit”的消息将会被丢弃,因为它们没有匹配任何bindingKey。
@RabbitListener(bindings = @QueueBinding(
key = "snStockStatus" + StringConstant.QUEUE_NORMAL,
value = @Queue(value = snQueue, durable = "true", ignoreDeclarationExceptions = "true"),
exchange = @Exchange(value = EventConfig.exchangeSROC, type = ExchangeTypes.TOPIC, durable = "true"),
ignoreDeclarationExceptions = "true"))
public void snStockReservedAvailable(@Payload Event event, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws IOException {
try {
service.reservedAvailable(event);
channel.basicAck(deliveryTag, false);
} catch (IOException e1) {
log.error(MQ错误{}", e1+JSONObject.toJSONString(event));
}
}