常用的交换机:
Direct Exchange
直连型交换机,根据消息携带的路由键将消息投递给对应队列。
大致流程,有一个队列绑定到一个直连交换机上,同时赋予一个路由键 routing key 。然后当一个消息携带着路由值为X,这个消息通过生产者发送给交换机时,交换机就会根据这个路由值X去寻找绑定值也是X的队列。
Fanout Exchange
扇型交换机,这个交换机没有路由键概念,就算你绑了路由键也是无视的。 这个交换机在接收到消息后,会直接转发到绑定到它上面的所有队列。
Topic Exchange
主题交换机,这个交换机其实跟直连交换机流程差不多,但是它的特点就是在它的路由键和绑定键之间是有规则的。
*(星号) 用来表示一个单词 (必须出现的)
#(井号) 用来表示任意数量(零个或多个)单词
1.创建两个springboot模块
一个 provider (生产者),一个consumer(消费者)。
provider模块
1.pom文件添加meven依赖
<!--rabbitmq-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
2.yml文件配置
server:
port: 8082
spring:
#给项目来个名字
application:
name: rabbitmq-provider
#配置rabbitMq 服务器
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
#消息确认配置项
2.先来分析直连型交换机 创建类DirectRabbitConfig.java
/**
* @Author : wbing
* @CreateTime : 2020/11/04
* @Description :直连型交换机,根据消息携带的路由键将消息投递给对应队列。
* 根据消费者带的路由键将消息投递给对应队列,大致流程,有一个队列绑定到一个直连交换机上,同时赋予一个路由键 routing key 。
* 然后当一个消息携带着路由值为X,这个消息通过生产者发送给交换机时,交换机就会根据这个路由值X去寻找绑定值也是X的队列。
**/
@Configuration
public class DirectRabbitConfig {
//队列 起名:TestDirectQueue
@Bean
public Queue TestDirectQueue() {
// durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
// exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
// autoDelete:是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。
// return new Queue("TestDirectQueue",true,true,false);
//一般设置一下队列的持久化就好,其余两个就是默认false
return new Queue("TestDirectQueue", true);
}
//Direct交换机 起名:TestDirectExchange
@Bean
DirectExchange TestDirectExchange() {
// return new DirectExchange("TestDirectExchange",true,true);
return new DirectExchange("TestDirectExchange", true, false);
}
//绑定 将队列和交换机绑定, 并设置用于匹配键:TestDirectRouting
@Bean
Binding bindingDirect() {
return BindingBuilder.bind(TestDirectQueue()).to(TestDirectExchange()).with("TestDirectRouting");
}
}
3.创建进项消息推送的方法 SendMessageController.java
/**
* @Author : wbing
* @CreateTime : 2020/11/04
* @Description :
**/
@RestController
public class SendMessageController {
@Autowired
RabbitTemplate rabbitTemplate; //使用RabbitTemplate,这提供了接收/发送等等方法
/**
* 测试 直连型交换机:路由TestDirectRouting 发送到交换机TestDirectExchange。
* 消费者模块的 DirectReceiver.java 会接收到信息,因为这个交换机绑定的键和这个消息携带的路由匹配
*/
@GetMapping("/sendDirectMessage")
public String sendDirectMessage() {
String messageId = String.valueOf(UUID.randomUUID());
String messageData = "嘻嘻哈哈嘿嘿";
String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Map<String, Object> map = new HashMap<>();
map.put("messageId", messageId);
map.put("messageData", messageData);
map.put("createTime", createTime);
//将消息携带绑定键值:TestDirectRouting 发送到交换机TestDirectExchange
rabbitTemplate.convertAndSend("TestDirectExchange", "TestDirectRouting", map);
return "ok";
}
}
4.运行项目 巧用接口测试 http://localhost:8082/sendDirectMessage
这时候已经准备好要消费 还没有要消费。
接下来创建消费者模块consumer
1.pom里添加maven依赖
<!--rabbitmq-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
2.application.yml配置
server:
port: 8083
spring:
#给项目来个名字
application:
name: rabbitmq-consumer
#配置rabbitMq 服务器
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
3.一样创建一个DirectRabbitConfig.java
/**
* @Author : wbing
* @CreateTime : 2020/11/04
* @Description : 消费者单纯的使用,其实可以不用添加这个配置,直接建后面的监听就好,使用注解来让监听器监听对应的队列即可。配置上了的话,其实消费者也是生成者的身份,也能推送该消息。
**/
@Configuration
public class DirectRabbitConfig {
//队列 起名:TestDirectQueue
@Bean
public Queue TestDirectQueue() {
return new Queue("TestDirectQueue", true);
}
//Direct交换机 起名:TestDirectExchange
@Bean
DirectExchange TestDirectExchange() {
return new DirectExchange("TestDirectExchange");
}
//绑定 将队列和交换机绑定, 并设置用于匹配键:TestDirectRouting
@Bean
Binding bindingDirect() {
return BindingBuilder.bind(TestDirectQueue()).to(TestDirectExchange()).with("TestDirectRouting");
}
}
4.创建消息监听类DirectReceiver.java 监听到生产者的列队发送的消息
/**
* @Author : wbing
* @CreateTime : 2020/11/04
* @Description : 监听生产者列队是TestDirectQueue名字的消息
**/
@Component
@RabbitListener(queues = "TestDirectQueue")//监听的队列名称 TestDirectQueue
public class DirectReceiver {
@RabbitHandler
public void process(Map testMessage) {
System.out.println("DirectReceiver消费者收到消息 : " + testMessage.toString());
}
}
5.启动consumer项目 就可以看到之前生产者发送的消息已经被消费者接收到了
二:主题交换机
1.provider项目里面创建TopicRabbitConfig.java
/**
* @Author : wbing
* @CreateTime : 2020/11/04
* @Description :主题交换机,这个交换机其实跟直连交换机流程差不多,但是它的特点就是在它的路由键和绑定键之间是有规则的。
* * (星号) 用来表示一个单词 (必须出现的)
* # (井号) 用来表示任意数量(零个或多个)单词
**/
@Configuration
public class TopicRabbitConfig {
//绑定键
public final static String man = "topic.man";
public final static String woman = "topic.woman";
//列队一
@Bean
public Queue firstQueue() {
return new Queue(TopicRabbitConfig.man);
}
//列队二
@Bean
public Queue secondQueue() {
return new Queue(TopicRabbitConfig.woman);
}
//交换机
@Bean
TopicExchange exchange() {
return new TopicExchange(" ");
}
//将firstQueue和topicExchange绑定,而且绑定的键值为topic.man
//这样只要是消息携带的路由键是topic.man,才会分发到该队列
@Bean
Binding bindingExchangeMessage() {
return BindingBuilder.bind(firstQueue()).to(exchange()).with(man);
}
//将secondQueue和topicExchange绑定,而且绑定的键值为用上通配路由键规则topic.#
// 这样只要是消息携带的路由键是以topic.开头,都会分发到该队列
@Bean
Binding bindingExchangeMessage2() {
return BindingBuilder.bind(secondQueue()).to(exchange()).with("topic.#");
}
}
- 然后添加多2个接口,用于推送消息到不同的主题交换机:
/**
* 主题交换机:发送消息到topicExchange的交换机,路由为topic.man
* 两个消费者模块的TopicManReceiver.java 和 TopicTotalReceiver.java都可以接收到消息,因为列队绑定的键都可以和这个消息携带的路由键匹配
*/
@GetMapping("/sendTopicMessage1")
public String sendTopicMessage1() {
String messageId = String.valueOf(UUID.randomUUID());
String messageData = "message: M A N ";
String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Map<String, Object> manMap = new HashMap<>();
manMap.put("messageId", messageId);
manMap.put("messageData", messageData);
manMap.put("createTime", createTime);
rabbitTemplate.convertAndSend("topicExchange", "topic.man", manMap);
return "ok";
}
/**
* 主题交换机:发送消息到topicExchange的交换机,路由为topic.woman
* 只有消费者模块TopicTotalReceiver.java接收到了信息,因为这个交换机只有一个列队的键与这个消息的路由键匹配
*/
@GetMapping("/sendTopicMessage2")
public String sendTopicMessage2() {
String messageId = String.valueOf(UUID.randomUUID());
String messageData = "message: woman is all ";
String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Map<String, Object> womanMap = new HashMap<>();
womanMap.put("messageId", messageId);
womanMap.put("messageData", messageData);
womanMap.put("createTime", createTime);
rabbitTemplate.convertAndSend("topicExchange", "topic.woman", womanMap);
return "ok";
}
3.去消费者创建对应的监听
TopicManReceiver.java 和 TopicTotalReceiver.java
/**
* @Author : wbing
* @CreateTime : 2020/11/04
* @Description :监听生产者列队是topic.man名字的消息
**/
@Component
@RabbitListener(queues = "topic.man")
public class TopicManReceiver {
@RabbitHandler
public void process(Map testMessage) {
System.out.println("TopicManReceiver消费者收到消息 : " + testMessage.toString());
}
}
/**
* @Author : wbing
* @CreateTime : 2020/11/04
* @Description :监听生产者列队是topic.woman名字的消息
**/
@Component
@RabbitListener(queues = "topic.woman")
public class TopicTotalReceiver {
@RabbitHandler
public void process(Map testMessage) {
System.out.println("TopicTotalReceiver消费者收到消息 : " + testMessage.toString());
}
}
4.同样,加主题交换机的相关配置 TopicRabbitConfig.java
/**
* @Author : wbing
* @CreateTime : 2020/11/04
* @Description :
**/
@Configuration
public class TopicRabbitConfig {
//绑定键
public final static String man = "topic.man";
public final static String woman = "topic.woman";
@Bean
public Queue firstQueue() {
return new Queue(TopicRabbitConfig.man);
}
@Bean
public Queue secondQueue() {
return new Queue(TopicRabbitConfig.woman);
}
@Bean
TopicExchange exchange() {
return new TopicExchange("topicExchange");
}
//将firstQueue和topicExchange绑定,而且绑定的键值为topic.man
//这样只要是消息携带的路由键是topic.man,才会分发到该队列
@Bean
Binding bindingExchangeMessage() {
return BindingBuilder.bind(firstQueue()).to(exchange()).with(man);
}
//将secondQueue和topicExchange绑定,而且绑定的键值为用上通配路由键规则topic.#
// 这样只要是消息携带的路由键是以topic.开头,都会分发到该队列
@Bean
Binding bindingExchangeMessage2() {
return BindingBuilder.bind(secondQueue()).to(exchange()).with("topic.#");
}
}
5.分别调用sendTopicMessage1
和 sendTopicMessage2: 可以看到消费的信息
三:扇型交换机
- provider项目上创建FanoutRabbitConfig.java
/**
* @Author : wbing
* @CreateTime : 2020/11/04
* @Description : 扇型交换机,这个交换机没有路由键概念,就算你绑了路由键也是无视的。 这个交换机在接收到消息后,会直接转发到绑定到它上面的所有队列。
**/
@Configuration
public class FanoutRabbitConfig {
/**
* 创建三个队列 :fan.outA fanout.B fanout.C
* 将三个队列都绑定在交换机 fanoutExchange 上
* 因为是交扇型换机, 路由键无需配置,配置也不起作用
*/
//列队A
@Bean
public Queue queueA() {
return new Queue("fanout.A");
}
//列队B
@Bean
public Queue queueB() {
return new Queue("fanout.B");
}
//列队C
@Bean
public Queue queueC() {
return new Queue("fanout.C");
}
//交换机
@Bean
FanoutExchange fanoutExchange() {
return new FanoutExchange("fanoutExchange");
}
//交换机绑定列队A
@Bean
Binding bindingExchangeA() {
return BindingBuilder.bind(queueA()).to(fanoutExchange());
}
//交换机绑定列队B
@Bean
Binding bindingExchangeB() {
return BindingBuilder.bind(queueB()).to(fanoutExchange());
}
//交换机绑定列队C
@Bean
Binding bindingExchangeC() {
return BindingBuilder.bind(queueC()).to(fanoutExchange());
}
}
2.写一个接口进行推送消息
/**
* 扇型交换机:发送消息到topicExchange的交换机,无路由
* 消费者模块FanoutReceiverA.java 和 FanoutReceiverB.java 和 FanoutReceiverC.java 都可以接收到消息。因为只要绑定的这个交换机的列队都可以接收到消息
*/
@GetMapping("/sendFanoutMessage")
public String sendFanoutMessage() {
String messageId = String.valueOf(UUID.randomUUID());
String messageData = "message: testFanoutMessage ";
String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Map<String, Object> map = new HashMap<>();
map.put("messageId", messageId);
map.put("messageData", messageData);
map.put("createTime", createTime);
rabbitTemplate.convertAndSend("fanoutExchange", null, map);
return "ok";
}
consumer项目里加上消息消费类监听 FanoutReceiverA.java
/**
* @Author : wbing
* @CreateTime : 2020/11/04
* @Description :监听生产者列队是fanout.A名字的消息
**/
@Component
@RabbitListener(queues = "fanout.A")
public class FanoutReceiverA {
@RabbitHandler
public void process(Map testMessage) {
System.out.println("FanoutReceiverA消费者收到消息 : " + testMessage.toString());
}
}
FanoutReceiverB.java
/**
* @Author : wbing
* @CreateTime : 2020/11/04
* @Description :监听生产者列队是fanout.B名字的消息
**/
@Component
@RabbitListener(queues = "fanout.B")
public class FanoutReceiverB {
@RabbitHandler
public void process(Map testMessage) {
System.out.println("FanoutReceiverB消费者收到消息 : " + testMessage.toString());
}
}
FanoutReceiverC.java
/**
* @Author : wbing
* @CreateTime : 2020/11/04
* @Description :监听生产者列队是fanout.C名字的消息
**/
@Component
@RabbitListener(queues = "fanout.C")
public class FanoutReceiverC {
@RabbitHandler
public void process(Map testMessage) {
System.out.println("FanoutReceiverC消费者收到消息 : " + testMessage.toString());
}
}
然后加上扇型交换机的配置类,FanoutRabbitConfig.java
/**
* @Author : wbing
* @CreateTime : 2020/11/04
* @Description :
**/
@Configuration
public class FanoutRabbitConfig {
/**
* 创建三个队列 :fan.outA fanout.B fanout.C
* 将三个队列都绑定在交换机 fanoutExchange 上
* 因为是交扇型换机, 路由键无需配置,配置也不起作用
*/
@Bean
public Queue queueA() {
return new Queue("fanout.A");
}
@Bean
public Queue queueB() {
return new Queue("fanout.B");
}
@Bean
public Queue queueC() {
return new Queue("fanout.C");
}
@Bean
FanoutExchange fanoutExchange() {
return new FanoutExchange("fanoutExchange");
}
@Bean
Binding bindingExchangeA() {
return BindingBuilder.bind(queueA()).to(fanoutExchange());
}
@Bean
Binding bindingExchangeB() {
return BindingBuilder.bind(queueB()).to(fanoutExchange());
}
@Bean
Binding bindingExchangeC() {
return BindingBuilder.bind(queueC()).to(fanoutExchange());
}
}
运行起来,调用接口 http://localhost:8082/sendFanoutMessage
这三个交换机介绍到此结束
接下来就是消息确认:生产者推送消息成功,消费者接收消息成功
配置:生产者模块yml 加上
#确认消息已发送到交换机(Exchange)
publisher-confirms: true
#确认消息已发送到队列(Queue)
publisher-returns: true
创建消息确认回调函数 RabbitConfig.java 。表示的是生产者推送消息是否成功的回调函数
/**
* @Author : wbing
* @CreateTime : 2020/11/04
* @Description : 消息确认:生产者推送消息成功的回调
**/
@Configuration
public class RabbitConfig {
/**
* 成功的和失败的情况:
* ①消息推送到server,但是在server里找不到交换机
* ②消息推送到server,找到交换机了,但是没找到队列
* ③消息推送到sever,交换机和队列啥都没找到
* ④消息推送成功
*/
@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 replyCode, String replyText, String exchange, String routingKey) {
System.out.println("ReturnCallback: " + "消息:" + message);
System.out.println("ReturnCallback: " + "回应码:" + replyCode);
System.out.println("ReturnCallback: " + "回应信息:" + replyText);
System.out.println("ReturnCallback: " + "交换机:" + exchange);
System.out.println("ReturnCallback: " + "路由键:" + routingKey);
}
});
return rabbitTemplate;
}
}
编写一个推送失败的例子
/**
* 测试 消息确认:这里是消息确认生产者接收消息成功的
* 会到RabbitConfig.java 错误的例子 触发ConfirmCallback 回调函数
*/
@GetMapping("/testMessageAck")
public String TestMessageAck() {
String messageId = String.valueOf(UUID.randomUUID());
String messageData = "message: non-existent-exchange test message ";
String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Map<String, Object> map = new HashMap<>();
map.put("messageId", messageId);
map.put("messageData", messageData);
map.put("createTime", createTime);
rabbitTemplate.convertAndSend("non-existent-exchange", "TestDirectRouting", map);
return "ok";
}
调用这个接口会发现
Channel shutdown: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'non-existent-exchange' in vhost 'JCcccHost', class-id=60, method-id=40)
ConfirmCallback: 相关数据:null
ConfirmCallback: 确认情况:false
ConfirmCallback: 原因:channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no exchange 'non-existent-exchange' in vhost 'JCcccHost', class-id=60, method-id=40)
再写一个成功的例子
/**
* 测试 消息确认:这里是消息确认生产者接收消息成功的
* 会到RabbitConfig.java 正确的例子
*/
@GetMapping("/TestMessageAck2")
public String TestMessageAck2() {
String messageId = String.valueOf(UUID.randomUUID());
String messageData = "message: lonelyDirectExchange test message ";
String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Map<String, Object> map = new HashMap<>();
map.put("messageId", messageId);
map.put("messageData", messageData);
map.put("createTime", createTime);
rabbitTemplate.convertAndSend("lonelyDirectExchange", "TestDirectRouting", map);
return "ok";
}
调用接口,查看provuder项目的控制台输出情况:
ReturnCallback: 消息:(Body:'{createTime=2019-09-04 09:48:01, messageId=563077d9-0a77-4c27-8794-ecfb183eac80, messageData=message: lonelyDirectExchange test message }' MessageProperties [headers={}, contentType=application/x-java-serialized-object, contentLength=0, receivedDeliveryMode=PERSISTENT, priority=0, deliveryTag=0])
ReturnCallback: 回应码:312
ReturnCallback: 回应信息:NO_ROUTE
ReturnCallback: 交换机:lonelyDirectExchange
ReturnCallback: 路由键:TestDirectRouting
ConfirmCallback: 相关数据:null
ConfirmCallback: 确认情况:true
ConfirmCallback: 原因:null
接下来就是消息接收 手动确认
在消费者项目里
新建MessageListenerConfig.java上添加代码相关的配置代码:
/**
* @Author : wbing
* @CreateTime : 2020/11/4
* @Description : 消息确认机制
**/
@Configuration
public class MessageListenerConfig {
@Autowired
private CachingConnectionFactory connectionFactory;
@Autowired
private MyAckReceiver myAckReceiver;//消息接收处理类
@Bean
public SimpleMessageListenerContainer simpleMessageListenerContainer() {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
container.setConcurrentConsumers(1);
container.setMaxConcurrentConsumers(1);
container.setAcknowledgeMode(AcknowledgeMode.MANUAL); // RabbitMQ默认是自动确认,这里改为手动确认消息
//设置一个队列
//container.setQueueNames("TestDirectQueue");
//如果同时设置多个如下: 前提是队列都是必须已经创建存在的。MyAckReceiver.java会有接收消息的手动处理
container.setQueueNames("TestDirectQueue", "fanout.A");
//另一种设置队列的方法,如果使用这种情况,那么要设置多个,就使用addQueues
//container.setQueues(new Queue("TestDirectQueue",true));
//container.addQueues(new Queue("TestDirectQueue2",true));
//container.addQueues(new Queue("TestDirectQueue3",true));
container.setMessageListener(myAckReceiver);
return container;
}
}
对应的手动确认消息监听类,MyAckReceiver.java
/**
* @Author : wbing
* @CreateTime : 2020/11/04
* @Description : 手动确认的消息监听类
**/
@Component
public class MyAckReceiver implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
//因为传递消息的时候用的map传递,所以将Map从Message内取出需要做些处理
String msg = message.toString();
String[] msgArray = msg.split("'");//可以点进Message里面看源码,单引号直接的数据就是我们的map消息数据
Map<String, String> msgMap = mapStringToMap(msgArray[1].trim(), 3);
String messageId = msgMap.get("messageId");
String messageData = msgMap.get("messageData");
String createTime = msgMap.get("createTime");
//接收TestDirectQueue列队的消息进行逻辑处理
if ("TestDirectQueue".equals(message.getMessageProperties().getConsumerQueue())) {
System.out.println("消费的消息来自的队列名为:" + message.getMessageProperties().getConsumerQueue());
System.out.println("消息成功消费到 messageId:" + messageId + " messageData:" + messageData + " createTime:" + createTime);
System.out.println("执行TestDirectQueue中的消息的业务处理流程......");
}
//接收fanout.A列队的消息进行逻辑处理
if ("fanout.A".equals(message.getMessageProperties().getConsumerQueue())) {
System.out.println("消费的消息来自的队列名为:" + message.getMessageProperties().getConsumerQueue());
System.out.println("消息成功消费到 messageId:" + messageId + " messageData:" + messageData + " createTime:" + createTime);
System.out.println("执行fanout.A中的消息的业务处理流程......");
}
//以下都表示消息已经被正确投递
/**
* 表示消息已经被正确处理
* 第一个参数依然是当前消息到的数据的唯一id;
* 第二个参数,手动确认可以被批处理,当该参数为 true 时,则可以一次性确认 delivery_tag 小于等于传入值的所有消息
*/
channel.basicAck(deliveryTag, true);
/**
* 表示消息没有被正确处理
* 第一个参数依然是当前消息到的数据的唯一id;
* 第二个参数,true会重新放回队列,那么下次还会消费这消息,所以需要自己根据业务逻辑判断什么时候使用拒绝
* 设置false,就是告诉服务器,我已经知道这条消息数据了,因为一些原因拒绝它,而且服务器也把这个消息丢掉就行。 下次不想再消费这条消息了。
*/
//channel.basicReject(deliveryTag, true);
/**
* 表示消息第一个参数依然是当前消息到的数据的唯一id;没有被正确处理
*
* 第二个参数是指是否针对多条消息;如果是true,也就是说一次性针对当前通道的消息的tagID小于当前这条消息的,都拒绝确认。
* 第三个参数是指是否重新入列,也就是指不确认的消息是否重新丢回到队列里面去。
*/
//channel.basicNack(deliveryTag, false, true);
} catch (Exception e) {
channel.basicReject(deliveryTag, false);
e.printStackTrace();
}
}
//{key=value,key=value,key=value} 格式转换成map
private Map<String, String> mapStringToMap(String str, int entryNum) {
str = str.substring(1, str.length() - 1);
String[] strs = str.split(",", entryNum);
Map<String, String> map = new HashMap<String, String>();
for (String string : strs) {
String key = string.split("=")[0].trim();
String value = string.split("=")[1];
map.put(key, value);
}
return map;
}
}
调用接口/sendDirectMessage 和 /sendFanoutMessage ,
可以手动确认一个或者多个列队,只需在MyAckReceiver.java里边,if判断一下就可以走各自的逻辑了
嘻嘻