1.rabbitmq的五种队列模式
- 简单队列
- 工作队列
- 发布、订阅
- 路由
- 主题
- rpc等
1.常用的交换机
因为消费者是从队列获取消息的,队列是绑定交换机的,所以对应的消息推送、接受模式有一下几种
-
Direct Exchange
-
路由模式是发布/订阅模式的一种特殊情况。
-
路由模式的交换机类型为“direct”。
-
绑定队列到交换机时指定 key,即
路由键
,一个队列可以指定多个路由键。 -
生产者发送消息时需要指定路由键,这时,消息只会发送到绑定的key的对应队列中。
直连型交换机,根据消息携带的路由键将消息投递给对应队列
-
-
Topic Exchange
- 将路由键和某模式进行匹配。此时,队列需要绑定到一个模式上。符号“#”匹配一个或多个词,“*”匹配一个词。
- 绑定队列到交换机指定key时,进行通配符模式匹配。
2.消息回调
1.生产者回调
server:
port: 8021
spring:
#项目名称
application:
name: rabbitmq-provider
#配置rabbitmq服务器
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
#虚拟host 可以不设置,使用server默认host
virtual-host: testhost
#消息确认配置项
#确认消息已发送到交换机
publisher-confirm-type: correlated
#确认消息已发送到队列
publisher-returns: true
package com.example.demo.config;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Created with Intellj IDEA.
*
* @Author: peter.zhang
* @Date: 2020-07-24
* @Time: 10:30
* @Description:
* @Version 1.0
*/
@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 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;
}
}
2.消费者回调
package com.example.demo.config;
import com.example.demo.receiver.MyAckReceiver;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@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", "fanout.A");
//如果同时设置多个如下: 前提是队列都是必须已经创建存在的
// container.setQueueNames("TestDirectQueue","TestDirectQueue2","TestDirectQueue3");
//另一种设置队列的方法,如果使用这种情况,那么要设置多个,就使用addQueues
//container.setQueues(new Queue("TestDirectQueue",true));
//container.addQueues(new Queue("TestDirectQueue2",true));
//container.addQueues(new Queue("topic.woman",true));
container.setMessageListener(myAckReceiver);
return container;
}
}
接受成功回调的方法
package com.example.demo.receiver;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@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());
String messageId = msgMap.get("messageId");
String messageData = msgMap.get("messageData");
String createTime = msgMap.get("createTime");
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中的消息的业务处理流程......");
}
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中的消息的业务处理流程......");
}
channel.basicAck(deliveryTag, true);
// channel.basicReject(deliveryTag, true);//为true会重新放回队列
} catch (Exception e) {
channel.basicReject(deliveryTag, false);
e.printStackTrace();
}
}
//{key=value,key=value,key=value} 格式转换成map
private Map<String, String> mapStringToMap(String str) {
str = str.substring(1, str.length() - 1);
String[] strs = str.split(",");
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;
}
}
g, String>();
for (String string : strs) {
String key = string.split("=")[0].trim();
String value = string.split("=")[1];
map.put(key, value);
}
return map;
}
}
参考:https://blog.csdn.net/qq_35387940/article/details/100514134