RabbitMQ三种主要交换机及消息确认机制

348 阅读3分钟

「这是我参与11月更文挑战的第24天,活动详情查看:2021最后一次更文挑战」。

直连型交换机

Direct Exchange,直连型交换机是根据消息投递的路由键找到对应绑定的队列

示例代码

  1. 首先在生产者和消费者中配置队列和交换机,并进行绑定,通过如下配置代码可知,队列在绑定到交换机时添加了路由键,这样生产者进行消息传送时只有投递到该交换机并有准确的路由键才能投递到具体的队列

@Configuration

public class DirectRabbitConfig {

@Bean

public Queue directQueue() {

//队列 起名:TestDirectQueue

return new Queue("directQueue", true);

}

//Direct交换机

@Bean

DirectExchange TestDirectExchange() {

return new DirectExchange("TestDirectExchange");

}

//绑定 将队列和交换机绑定,并设置路由键

@Bean

Binding bindingDirect() {

return BindingBuilder.bind(directQueue()).to(TestDirectExchange()).with("TestDirectRouting");

}

}

controller层消息传递代码

通过rabbitTemplate调用传递的方法,传参就是交换机的名字,路由,以及具体的信息


public class SendMessageController {

@Autowired

RabbitTemplate rabbitTemplate;

@GetMapping("/sendDirectMessage")

public String sendDirectMessage() {

// HashMap hashMap = new HashMap();

// hashMap.put("key", "value");

String msg = "fanoutExchange";

rabbitTemplate.convertAndSend("TestDirectExchange","TestDirectRouting", msg);

return "ok";

}

Fanout Exchange(扇形交换机)

扇形交换机就是没有路由键,消息传递给交换机,交换机就会把消息分发到绑定的队列中

Topic Exchange (主题交换机)

主题交换机也是通过路由键去匹配,但是它比直连型多了一个模糊匹配

*  (星号) 用来表示一个单词 (必须出现的)

#  (井号) 用来表示任意数量(零个或多个)单词

通配的绑定键是跟队列进行绑定的,举个小例子

队列Q1 绑定键为 .TT.          队列Q2绑定键为  TT.#

如果一条消息携带的路由键为 A.TT.B,那么队列Q1将会收到;

如果一条消息携带的路由键为TT.AA.BB,那么队列Q2将会收到;

生产者消息确认模式

一般生成者在发送消息到rabbitmq时,可能会存在没有找到交换机,或者找到交换机但没找到队列等情况

代码示例

生产者消息确认模式,需要在生产者配置文件里先进行配置

然后配置相关消息的回调函数


@Configuration

public class RabbitConfig {

@Bean

public RabbitTemplate createRabbitTemplate(ConnectionFactory connectionFactory) {

RabbitTemplate rabbitTemplate = new RabbitTemplate();

rabbitTemplate.setConnectionFactory(connectionFactory);

//设置开启Mandatory,才能触发回调函数,无论消息推送结果怎么样都强制调用回调函数

rabbitTemplate.setMandatory(true);

rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {

@Override

public void confirm(CorrelationData correlationData, boolean ack, String cause) {

System.out.println("ConfirmCallback" + "相关数据: " + correlationData);

System.out.println("ConfirmCallback" + "确认情况" + ack);

System.out.println("ConfirmCallback" + "原因" + cause);

}

});

rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {

@Override

public void returnedMessage(Message message, int i, String s, String s1, String s2) {

System.out.println("ReturnCallback: " + "消息:" + message);

System.out.println("ReturnCallback: " + "回应码:" + i);

System.out.println("ReturnCallback: " + "回应信息:" + s);

System.out.println("ReturnCallback: " + "交换机:" + s1);

System.out.println("ReturnCallback: " + "路由键:" + s2);

}

});

return rabbitTemplate;

}

}

从代码可知,主要有两个回调函数,一个是confirmCallback,一个是returnCallback,这两者会在不同的场景进行触发

1.消息推送到server,但是在server里找不到交换机

这种情况就会调用confirmCallback

  1. 消息推送到server,找到交换机了,但是没找到队列

两者都会触发

③消息推送到sever,交换机和队列啥都没找到

跟第一种情况相同

④消息推送成功

会触发confirmCallback

消费者接收消息确认机制

消费者消息确认机制主要分为自动确认和手动确认

自动确认

默认配置就是自动确认,当mq将消息发给消费者,无论消费者有没有消费成功,都会默认成功,并将该消息从队列中移除

手动确认

消费者收到消息后,手动调用basic.ack/basic.nack/basic.reject后,RabbitMQ收到这些消息后,才认为本次投递成功。

basic.ack用于肯定确认 

basic.nack用于否定确认(注意:这是AMQP 0-9-1的RabbitMQ扩展) 

basic.reject用于否定确认,但与basic.nack相比有一个限制:一次只能拒绝单条消息 

消费者端以上的3个方法都表示消息已经被正确投递,但是basic.ack表示消息已经被正确处理,但是basic.nack,basic.reject表示没有被正确处理,但是RabbitMQ中仍然需要删除这条消息。