文章目录
RabbitMQ介绍
百度百科:
RabbitMQ是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。RabbitMQ服务器是用Erlang语言编写的,而集群和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均有与代理接口通讯的客户端库。
AMQP协议:
AMQP |
---|
![]() |
Erlang:Erlang是一种通用的面向并发的编程语言,Erlang充分发挥CPU的性能,延迟特别低,相比其他的MQ(Kafka,RocketMQ)延迟是最低的。
RabbitMQ支持多种语言通讯:Java,Python…………都有响应的API
RabbitMQ支持海量的插件去实现一些特殊功能,RabbitMQ自带了一款图形化界面,操作异常的简单。
RabbitMQ安装
Docker安装RabbitMQ (安装带有管理控制台的镜像):
docker run -d --name rabbitmq -p 5671:5671 -p 5672:5672 -p 4369:4369 -p 25672:25672 -p 15671:15671 -p 15672:15672 -v /opt/rabbitmq:/var/lib/rabbitmq rabbitmq:management
端口说明:
4369, 25672 (Erlang发现&集群端口)
5672, 5671 (AMQP端口)
15672 (web管理后台端口)
61613, 61614 (STOMP协议端口)
1883, 8883 (MQTT协议端口)
RabbitMQ架构
完整架构 |
---|
![]() |
RabbitMQ通讯方式
RabbitMQ提供的通讯方式
-
Hello World!:为了入门操作!
-
Work queues:一个队列被多个消费者消费
-
Publish/Subscribe:手动创建Exchange(FANOUT)
-
Routing:手动创建Exchange(DIRECT)
-
Topics:手动创建Exchange(TOPIC)
-
RPC:RPC方式
-
Publisher Confirms:保证消息可靠性
构建Connection工具类
- 导入依赖:amqp-client,junit
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.10.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
- 构建工具类
public class RabbitMqConnectionUtil {
public static final String RABBITMQ_HOST = "127.0.0.1";
public static final int RABBITMQ_PORT = 5672;
public static final String RABBITMQ_USERNAME = "guest";
public static final String RABBITMQ_PASSWORD = "guest";
public static final String RABBITMQ_VIRTUAL_HOST = "/";
public static Connection getConnection() throws Exception {
//1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置连接信息
factory.setHost(RABBITMQ_HOST);
factory.setPort(RABBITMQ_PORT);
factory.setUsername(RABBITMQ_USERNAME);
factory.setPassword(RABBITMQ_PASSWORD);
factory.setVirtualHost(RABBITMQ_VIRTUAL_HOST);
//3.创建连接
Connection connection = factory.newConnection();
return connection;
}
}
Hello World
通讯方式 |
---|
![]() |
- 生产者:
public class Publisher {
public static final String QUEUE_NAME = "hello";
@Test
public void publish() throws Exception{
//1.获取连接
Connection connection = RabbitMqConnectionUtil.getConnection();
//2.构建channel
Channel channel = connection.createChannel();
//3.构建队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//4.发布消息
channel.basicPublish("",QUEUE_NAME,null,"Hello World".getBytes());
}
}
- 消费者
public class Consumer {
public static final String QUEUE_NAME = "hello";
@Test
public void consume() throws Exception{
//1.获取连接
Connection connection = RabbitMqConnectionUtil.getConnection();
//2.构建channel
Channel channel = connection.createChannel();
//3.构建队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//4.监听消息
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String s, Envelope envelope, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
System.out.println("消费者获取到消息:" + new String(bytes,"UTF-8"));
}
};
channel.basicConsume(QUEUE_NAME,true,consumer);
System.in.read();
}
}
Work Queues
WorkQueues需要学习的内容 |
---|
![]() |
- 生产者:生产者和Hello World的形式是一样的,都是将消息推送到默认交换机。
- 消费者:让消费者关闭自动ack,并且设置消息的流控,最终实现消费者可以尽可能去多消费消息
public class Consumer {
public static final String QUEUE_NAME = "workqueues";
@Test
public void consume1() throws Exception{
//1.获取连接
Connection connection = RabbitMqConnectionUtil.getConnection();
//2.构建channel
Channel channel = connection.createChannel();
//3.构建队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//4.设置消息的流控
channel.basicQos(3);
//5.监听消息
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String s, Envelope envelope, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
System.out.println("消费者1号获取到消息:" + new String(bytes,"UTF-8"));
//6.关闭自动ack
channel.basicAck(envelope.getDeliveryTag(),false);
}
};
channel.basicConsume(QUEUE_NAME,true,consumer);
System.in.read();
}
@Test
public void consume2() throws Exception{
//1.获取连接
Connection connection = RabbitMqConnectionUtil.getConnection();
//2.构建channel
Channel channel = connection.createChannel();
//3.构建队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//4.设置消息的流控
channel.basicQos(1);
//5.监听消息
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String s, Envelope envelope, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
System.out.println("消费者2号获取到消息:" + new String(bytes,"UTF-8"));
//6.关闭自动ack
channel.basicAck(envelope.getDeliveryTag(),false);
}
};
channel.basicConsume(QUEUE_NAME,true,consumer);
System.in.read();
}
}
Publish/Subscribe
自定义一个交换机 |
---|
![]() |
- 生产者:自行构建Exchange并绑定指定队列(FANOUT类型)
- 消费者同上
public class Publisher {
public static final String EXCHANGE_NAME = "pubsub";
public static final String QUEUE_NAME1 = "pubsub-one";
public static final String QUEUE_NAME2 = "pubsub-two";
@Test
public void publish() throws Exception{
//1.获取连接
Connection connection = RabbitMqConnectionUtil.getConnection();
//2.构建channel
Channel channel = connection.createChannel();
//3.构建交换机
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
//4.构建队列
channel.queueDeclare(QUEUE_NAME1,false,false,false,null);
channel.queueDeclare(QUEUE_NAME2,false,false,false,null);
//5.绑定队列
channel.queueBind(QUEUE_NAME1,EXCHANGE_NAME,"");
channel.queueBind(QUEUE_NAME2,EXCHANGE_NAME,"");
//6.发送消息到交换机
channel.basicPublish(EXCHANGE_NAME,"",null,"publish/subscribe!".getBytes());
}
}
Routing
DIRECT类型Exchange |
---|
![]() |
- 生产者:在绑定Exchange和Queue时,需要指定好routingKey,同时在发送消息时,也指定routingKey,只有routingKey一致时,才会把指定的消息路由到指定的Queue
- 消费者同上
public class Publisher {
public static final String EXCHANGE_NAME = "routing";
public static final String QUEUE_NAME1 = "routing-one";
public static final String QUEUE_NAME2 = "routing-two";
@Test
public void publish() throws Exception{
//1.获取连接
Connection connection = RabbitMqConnectionUtil.getConnection();
//2.构建channel
Channel channel = connection.createChannel();
//3.构建交换机
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
//4.构建队列
channel.queueDeclare(QUEUE_NAME1,false,false,false,null);
channel.queueDeclare(QUEUE_NAME2,false,false,false,null);
//5.绑定队列
channel.queueBind(QUEUE_NAME1,EXCHANGE_NAME,"orange");
channel.queueBind(QUEUE_NAME2,EXCHANGE_NAME,"black");
channel.queueBind(QUEUE_NAME2,EXCHANGE_NAME,"white");
//6.发送消息到交换机
channel.basicPublish(EXCHANGE_NAME,"orange",null,"大橙子".getBytes());
channel.basicPublish(EXCHANGE_NAME,"black",null,"大黑狗".getBytes());
channel.basicPublish(EXCHANGE_NAME,"white",null,"大白狗".getBytes());
}
}
Topic
Topic模式 |
---|
![]() |
- 生产者:TOPIC类型可以编写带有特殊意义的routingKey的绑定方式
public class Publisher {
public static final String EXCHANGE_NAME = "topic";
public static final String QUEUE_NAME1 = "topic-one";
public static final String QUEUE_NAME2 = "topic-two";
@Test
public void publish() throws Exception{
//1.获取连接
Connection connection = RabbitMqConnectionUtil.getConnection();
//2.构建channel
Channel channel = connection.createChannel();
//3.构建交换机
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
//4.构建队列
channel.queueDeclare(QUEUE_NAME1,false,false,false,null);
channel.queueDeclare(QUEUE_NAME2,false,false,false,null);
//5. 绑定交换机和队列,
// TOPIC类型的交换机在和队列绑定时,需要以aaa.bbb.ccc..方式编写routingkey
// 其中有两个特殊字符:*(相当于占位符),#(相当通配符)
channel.queueBind(QUEUE_NAME1,EXCHANGE_NAME,"*.orange.*");
channel.queueBind(QUEUE_NAME2,EXCHANGE_NAME,"*.*.black");
channel.queueBind(QUEUE_NAME2,EXCHANGE_NAME,"white.#");
//6.发送消息到交换机
channel.basicPublish(EXCHANGE_NAME,"big.orange.yellow",null,"黄色大橙子".getBytes());
channel.basicPublish(EXCHANGE_NAME,"lazy.big.black",null,"大懒黑狗".getBytes());
channel.basicPublish(EXCHANGE_NAME,"white.small.dog",null,"白色小狗".getBytes());
}
}
RPC
因为两个服务在交互时,可以尽量做到Client和Server的解耦,通过RabbitMQ进行解耦操作
需要让Client发送消息时,携带两个属性:
replyTo告知Server将相应信息放到哪个队列
correlationId告知Server发送相应消息时,需要携带位置标示来告知Client响应的信息
Topic模式 |
---|
![]() |
- 客户端
public class Publisher {
public static final String QUEUE_PUBLISHER = "rpc_publisher";
public static final String QUEUE_CONSUMER = "rpc_consumer";
@Test
public void publish() throws Exception{
//1.获取连接
Connection connection = RabbitMqConnectionUtil.getConnection();
//2.构建channel
Channel channel = connection.createChannel();
//3.构建队列
channel.queueDeclare(QUEUE_PUBLISHER,false,false,false,null);
channel.queueDeclare(QUEUE_CONSUMER,false,false,false,null);
//4.发送消息
String uuid = UUID.randomUUID().toString();
String message = "hello rpc";
AMQP.BasicProperties basicProperties = new AMQP.BasicProperties().builder()
.replyTo(QUEUE_CONSUMER)
.correlationId(uuid)
.build();
channel.basicPublish("",QUEUE_PUBLISHER,basicProperties,message.getBytes());
//5.消费消息
channel.basicConsume(QUEUE_CONSUMER,false,new DefaultConsumer(channel){
@Override
public void handleDelivery(String s, Envelope envelope, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
String id = basicProperties.getCorrelationId();
if (id != null && id.equals(uuid)){
System.out.println("接收到服务端的响应:" + new String(bytes,"UTF-8"));
}
//关闭自动ack
channel.basicAck(envelope.getDeliveryTag(),false);
}
});
System.in.read();
}
}
- 服务端
public class Consumer {
public static final String QUEUE_PUBLISHER = "rpc_publisher";
public static final String QUEUE_CONSUMER = "rpc_consumer";
@Test
public void consume() throws Exception{
//1.获取连接
Connection connection = RabbitMqConnectionUtil.getConnection();
//2.构建channel
Channel channel = connection.createChannel();
//3.构建队列
channel.queueDeclare(QUEUE_PUBLISHER,false,false,false,null);
channel.queueDeclare(QUEUE_CONSUMER,false,false,false,null);
//4.监听消息
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String s, Envelope envelope, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
System.out.println("消费者获取到消息:" + new String(bytes,"UTF-8"));
String resp = "获取到了client发出的请求,这里是响应的信息";
String respQueueName = basicProperties.getReplyTo();
String uuid = basicProperties.getCorrelationId();
AMQP.BasicProperties props = new AMQP.BasicProperties()
.builder()
.correlationId(uuid)
.build();
channel.basicPublish("",respQueueName,props,resp.getBytes());
//关闭自动ack
channel.basicAck(envelope.getDeliveryTag(),false);
}
};
channel.basicConsume(QUEUE_PUBLISHER,true,consumer);
System.in.read();
}
}
SpringBoot操作RabbitMQ
SpringBoot声明信息
-
创建项目
-
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
- 配置RabbitMQ信息
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtual-host: /
- 声明交换机&队列
@Configuration
public class RabbitMqConfig {
public static final String EXCHANGE = "boot-exchange";
public static final String QUEUE = "boot-queue";
public static final String ROUTING_KEY = "*.black.*";
/**
* 创建交换机
* @return
*/
@Bean
public Exchange bootExchange(){
return ExchangeBuilder.topicExchange(EXCHANGE).build();
}
/**
* 创建队列
* @return
*/
@Bean
public Queue bootQueue(){
return QueueBuilder.durable(QUEUE).build();
}
/**
* 绑定交换机队列
* @return
*/
@Bean
public Binding bootBinding(){
return BindingBuilder.bind(bootQueue()).to(bootExchange()).with(ROUTING_KEY).noargs();
}
}
生产者
@SpringBootTest
public class PublisherTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void publish(){
rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE, "big.black.dog", "大黑狗", new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setCorrelationId("123456789");
return message;
}
});
}
}
消费者
@Component
public class ConsumeListener {
/**
* 监听队列
*/
@RabbitListener(queues = {RabbitMqConfig.QUEUE})
public void consume(Channel channel, Message message) throws Exception{
System.out.println("获取消息:"+ new String(message.getBody()));
String correlationId = message.getMessageProperties().getCorrelationId();
System.out.println("唯一标识为:" + correlationId);
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
}
}
RabbitMQ保证消息可靠性
保证消息一定送达到Exchange
- Confirm机制
可以通过Confirm效果保证消息一定送达到Exchange,官方提供了三种方式,选择了对于效率影响最低的异步回调的效果
//开启confirms
channel.confirmSelect();
//设置confirms的异步回调
channel.addConfirmListener(new ConfirmListener() {
@Override
public void handleAck(long deliveryTag, boolean multiple) throws IOException {
System.out.println("消息成功的发送到Exchange!");
}
@Override
public void handleNack(long deliveryTag, boolean multiple) throws IOException {
System.out.println("消息没有发送到Exchange,尝试重试,或者保存到数据库做其他补偿操作!");
}
});
保证消息可以路由到Queue
- Return机制
// 设置Return回调,确认消息是否路由到了Queue
channel.addReturnListener(new ReturnListener() {
@Override
public void handleReturn(int replyCode, String replyText, String exchange, String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消息没有路由到指定队列,做其他的补偿措施!!");
}
});
// 在发送消息时,将basicPublish方法参数中的mandatory设置为true,即可开启Return机制,当消息没有路由到队列中时,就会执行return回调
channel.basicPublish(EXCHANGE_NAME,"big.orange.yellow",true,null,"黄色大橙子".getBytes());
保证Queue可以持久化消息
-
DeliveryMode设置消息持久化
-
DeliveryMode设置为2代表持久化,如果设置为1,就代表不会持久化
//7. 设置消息持久化
AMQP.BasicProperties props = new AMQP.BasicProperties()
.builder()
.deliveryMode(2)
.build();
channel.basicPublish(EXCHANGE_NAME,"big.orange.yellow",true,props,"黄色大橙子".getBytes());
保证消费者可以正常消费消息
- 消费者开启手动ack
SpringBoot实现上述操作
- 配置
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtual-host: /
publisher-confirm-type: correlated #开启confirm
publisher-returns: true #开启returns
- 代码实现
@SpringBootTest
public class PublisherTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void publish(){
//开启confirm
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if(ack){
System.out.println("消息已经送达到交换机!!");
}else{
System.out.println("消息没有送达到Exchange,需要做一些补偿操作!!retry!!!");
}
}
});
//开启return
rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
@Override
public void returnedMessage(ReturnedMessage returned) {
String msg = new String(returned.getMessage().getBody());
System.out.println("消息:" + msg + "路由队列失败!!做补救操作!!");
}
});
rabbitTemplate.convertAndSend(RabbitMqConfig.EXCHANGE, "big.black.dog", "大黑狗", new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setCorrelationId("123456789");
//设置消息持久化
message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
return message;
}
});
}
}
RabbitMQ死信队列&延迟交换机
死信介绍
死信&死信队列 |
---|
![]() |
- 死信队列的应用:
1.基于死信队列在队列消息已满的情况下,消息也不会丢失。
2.实现延迟消费的效果。比如:下订单时,有15分钟的付款时间。
实现死信队列
- 准备Exchange&Queue
@Configuration
public class DeadLetterConfig {
public static final String NORMAL_EXCHANGE = "normal-exchange";
public static final String NORMAL_QUEUE = "normal-queue";
public static final String NORMAL_ROUTING_KEY = "normal.key";
public static final String DEAD_EXCHANGE = "dead-exchange";
public static final String DEAD_QUEUE = "dead-queue";
public static final String DEAD_ROUTING_KEY = "dead.key";
@Bean
public Exchange normalExchange(){
return ExchangeBuilder.topicExchange(NORMAL_EXCHANGE).build();
}
/**
* 构建普通队列,同时将队列通过死信key绑定死信交换机
* @return
*/
@Bean
public Queue normalQueue(){
return QueueBuilder.durable(NORMAL_QUEUE).deadLetterExchange(DEAD_EXCHANGE)
.deadLetterRoutingKey(DEAD_ROUTING_KEY).build();
}
@Bean
public Binding normalBinding(){
return BindingBuilder.bind(normalQueue()).to(normalExchange()).with(NORMAL_ROUTING_KEY).noargs();
}
@Bean
public Exchange deadExchange(){
return ExchangeBuilder.topicExchange(DEAD_EXCHANGE).build();
}
@Bean
public Queue deadQueue(){
return QueueBuilder.durable(DEAD_QUEUE).build();
}
@Bean
public Binding deadBinding(){
return BindingBuilder.bind(deadQueue()).to(deadExchange()).with(DEAD_ROUTING_KEY).noargs();
}
}
- 实现
- 基于消费者进行reject或者nack实现死信效果
@Component
public class DeadListener {
@RabbitListener(queues = {DeadLetterConfig.NORMAL_QUEUE})
public void consume(Channel channel, Message message) throws Exception{
//reject
channel.basicReject(message.getMessageProperties().getDeliveryTag(),false);
//nack
channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,false);
}
}
- 消息的生存时间
给消息设置生存时间
@SpringBootTest
public class DeadPublishTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void publishExpire(){
String msg = "dead letter expire";
rabbitTemplate.convertAndSend(DeadLetterConfig.NORMAL_EXCHANGE, "normal.key", msg, new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setExpiration("5000");
return message;
}
});
}
}
给队列设置消息的生存时间
@Bean
public Queue normalQueue(){
return QueueBuilder.durable(NORMAL_QUEUE)
.deadLetterExchange(DEAD_EXCHANGE)
.deadLetterRoutingKey(NORMAL_ROUTING_KEY)
.ttl(10000)
.build();
}
- 设置Queue中的消息最大长度
@Bean
public Queue normalQueue(){
return QueueBuilder.durable(NORMAL_QUEUE)
.deadLetterExchange(DEAD_EXCHANGE)
.deadLetterRoutingKey(NORMAL_ROUTING_KEY)
.maxLength(1)
.build();
}
只要Queue中已经有一个消息,如果再次发送一个消息,这个消息会变为死信!
延迟交换机
- 下载地址:https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases/download/3.10.2/rabbitmq_delayed_message_exchange-3.10.2.ez
1)将下载的插件复制到容器中
docker cp rabbitmq_delayed_message_exchange-3.10.2.ez rabbitmq:/opt/rabbitmq/plugins
进入容器:docker exec -it rabbitmq bash
2)到/opt/rabbitmq/sbin下
rabbitmq-plugins rabbitmq_delayed_message_exchange
3)退出容器:exit,重启容器:docker restart rabbitmq
- 延迟交换机队列配置
@Configuration
public class DelayedConfig {
public static final String DELAYED_EXCHANGE = "delayed-exchange";
public static final String DELAYED_QUEUE = "delayed-queue";
public static final String DELAYED_ROUTING_KEY = "delayed.key";
/**
* 构建延迟队列
* @return
*/
@Bean
public Exchange delayedExchange(){
Map<String,Object> arguments = new HashMap<>();
arguments.put("x-delayed-type","topic");
Exchange exchange = new CustomExchange(DELAYED_EXCHANGE,"x-delayed-message",true,false,arguments);
return exchange;
}
@Bean
public Queue delayedQueue(){
return QueueBuilder.durable(DELAYED_QUEUE).build();
}
@Bean
public Binding delayedBinding(){
return BindingBuilder.bind(delayedQueue()).to(delayedExchange()).with(DELAYED_ROUTING_KEY).noargs();
}
}
- 延迟消息发送
@SpringBootTest
public class DelayedPublishTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void publishExpire(){
String msg = "this is delayed message";
rabbitTemplate.convertAndSend(DelayedConfig.DELAYED_EXCHANGE, DelayedConfig.DELAYED_ROUTING_KEY, msg, new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
//设置延迟时间
message.getMessageProperties().setDelay(2000);
return message;
}
});
}
}
RabbitMQ其他内容
Headers类型Exchange
headers就是一个基于key-value的方式,让Exchange和Queue绑定的到一起的一种规则
相比Topic形式,可以采用的类型更丰富。
headers绑定方式 |
---|
![]() |
- 原生
public class Publisher {
public static final String HEADER_EXCHANGE = "header-exchange";
public static final String HEADER_QUEUE = "header-queue";
@Test
public void publish() throws Exception{
//1.获取连接
Connection connection = RabbitMqConnectionUtil.getConnection();
//2.构建channel
Channel channel = connection.createChannel();
//3.构建交换机
channel.exchangeDeclare(HEADER_EXCHANGE, BuiltinExchangeType.HEADERS);
//4.构建队列
channel.queueDeclare(HEADER_QUEUE,false,false,false,null);
Map<String,Object> args = new HashMap<>();
// 多个header的key-value只要可以匹配上一个就可以
// args.put("x-match","any");
// 多个header的key-value要求全部匹配上!
args.put("x-match","all");
args.put("name","jack");
args.put("age","23");
//5.绑定队列
channel.queueBind(HEADER_QUEUE,HEADER_EXCHANGE,"",args);
//6.发送消息到交换机
String msg = "header测试消息!";
Map<String, Object> headers = new HashMap<>();
headers.put("name","jack");
headers.put("age","23");
AMQP.BasicProperties props = new AMQP.BasicProperties()
.builder()
.headers(headers)
.build();
channel.basicPublish(HEADER_EXCHANGE,"",true,props,msg.getBytes());
}
}
- springboot
- 构建交换机队列
@Configuration
public class HeadersConfig {
public static final String HEADERS_EXCHANGE = "headers-exchange";
public static final String HEADERS_QUEUE = "headers-queue";
/**
* 构建队列
* @return
*/
@Bean
public HeadersExchange headersExchange(){
return ExchangeBuilder.headersExchange(HEADERS_EXCHANGE).build();
}
@Bean
public Queue headersQueue(){
return QueueBuilder.durable(HEADERS_QUEUE).build();
}
@Bean
public Binding headersBinding(){
Map<String,Object> headerKeys = new HashMap<>();
headerKeys.put("name","jack");
headerKeys.put("age",23);
//BindingBuilder.bind(headersQueue()).to(headersExchange()).whereAny(headerKeys).match();
return BindingBuilder.bind(headersQueue()).to(headersExchange()).whereAll(headerKeys).match();
}
}
- 消息生产
@SpringBootTest
public class HeadersPublishTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void publish(){
String msg = "this is headers message";
//Message message = MessageBuilder.withBody(msg.getBytes()).setHeader("","").build();
MessageProperties properties = new MessageProperties();
properties.setHeader("name","jack");
properties.setHeader("age",23);
Message message = new Message(msg.getBytes(),properties);
rabbitTemplate.convertAndSend(HeadersConfig.HEADERS_EXCHANGE, "", message, new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
return message;
}
});
}
}