RabbitMQ 工作模式

简单模式
  • 简单:一个生产者、一个队列和一个消费者,生产者发送消息至队列,消费者监听队列并消费消息

Work 模式
  • Work:一个生产者、一个队列和多个消费者,生产者发送消息至队列,多个消费者监听同一队列消费消息

发布/订阅模式
  • 发布/订阅:publish/subscribe 模式包含一个生产者、一个交换机、多个队列及多个消费者,交换机(Exchange)和队列直接绑定,生产者通过交换机(Exchange)将消息存储在与交换机绑定的队列中,消费者监听队列并进行消费

路由模式
  • 路由:routing 模式可以根据 routing key 将消息发送给指定队列,交换机(Exchange)和队列通过routing key 进行绑定,生产者通过交换机(Exchange)和 routing key 将消息精准发送至队列,消费者监听队列并消费消息

主题模式
  • 主题:Topics 模式在路由模式的基础上支持通配符操作,交换机会根据通配符将消息存储在匹配成功的队列中,消费者监听队列并进行消费

Header 模式
  • Header:header 模式取消了 routing key,而是使用 header 中的 key/value 键值对来进行匹配,匹配成功后消息会通过交换机发送给队列,消息者才能获取到消息并消费

RPC 模式
  • RPC:RPC 模式主要针对需要获取消费者处理结果的情况,通常是生产者将消息发送给了消费者,消费者接收到消息并进行消费后返回给生产者处理结果

SpringBoot 集成 RabbitMQ

  • 首先创建一个SpringBoot 项目,pom.xml 文件加入以下依赖
<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>
  • 配置文件修改,加入以下 RabbitMQ 配置
server:
  port: 8888  # 设置端口号

spring:
  rabbitmq:
    host: 127.0.0.1  # 设置RabbitMQ所在主机
    port: 5672       # 设置RabbitMQ服务端口
    username: guest  # 设置RabbitMQ用户名
    password: guest  # 设置RabbitMQ密码
  • 新增公共常量类
public interface RabbitConstant {

    /**
     * 简单模式
     */
    String SIMPLE_QUEUE_NAME = "simple_queue";

    /**
     * work 模式
     */
    String WORK_QUEUE_NAME = "work_queue";

    /**
     * 发布/订阅(publish/subscribe)模式
     */
    String PUBLISH_SUBSCRIBE_EXCHANGE_NAME = "publish_subscribe_exchange";
    String PUBLISH_SUBSCRIBE_FIRST_QUEUE_NAME = "publish_subscribe_first_queue";
    String PUBLISH_SUBSCRIBE_SECOND_QUEUE_NAME = "publish_subscribe_second_queue";

    /**
     * 路由(routing)模式
     */
    String ROUTING_EXCHANGE_NAME = "routing_exchange";
    String ROUTING_FIRST_QUEUE_NAME = "routing_first_queue";
    String ROUTING_SECOND_QUEUE_NAME = "routing_second_queue";
    String ROUTING_THIRD_QUEUE_NAME = "routing_third_queue";
    String ROUTING_FIRST_QUEUE_ROUTING_KEY_NAME = "routing_first_queue_routing_key";
    String ROUTING_SECOND_QUEUE_ROUTING_KEY_NAME = "routing_second_queue_routing_key";
    String ROUTING_THIRD_QUEUE_ROUTING_KEY_NAME = "routing_third_queue_routing_key";

    /**
     * 主题(topics)模式
     */
    String TOPICS_EXCHANGE_NAME = "topics_exchange";
    String TOPICS_FIRST_QUEUE_NAME = "topics_first_queue";
    String TOPICS_SECOND_QUEUE_NAME = "topics_second_queue";
    String TOPICS_THIRD_QUEUE_NAME = "topics_third_queue";
    String TOPICS_FIRST_QUEUE_ROUTING_KEY = "topics.first.routing.key";
    String TOPICS_SECOND_QUEUE_ROUTING_KEY = "topics.second.routing.key";
    String TOPICS_THIRD_QUEUE_ROUTING_KEY = "topics.third.routing.key";
    String TOPICS_ROUTING_KEY_FIRST_WILDCARD = "#.first.#";
    String TOPICS_ROUTING_KEY_SECOND_WILDCARD = "*.second.#";
    String TOPICS_ROUTING_KEY_THRID_WILDCARD = "*.third.*";

    /**
     * header 模式
     */
    String HEADER_EXCHANGE_NAME = "header_exchange";
    String HEADER_FIRST_QUEUE_NAME = "header_first_queue";
    String HEADER_SECOND_QUEUE_NAME = "header_second_queue";

    /**
     * rpc 模式
     */
    String RPC_QUEUE_NAME = "rpc_queue";

}
  • 新增 Controller 请求类(用于验证结果,可最后新增)
import com.example.rabbitmq.constant.RabbitConstant;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.nio.charset.StandardCharsets;

@RestController
public class RabbitController {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @GetMapping(value = "/simple")
    public void simple() {
        rabbitTemplate.convertAndSend(RabbitConstant.SIMPLE_QUEUE_NAME, "hello world!");
    }

    @GetMapping(value = "/work")
    public void work() {
        rabbitTemplate.convertAndSend(RabbitConstant.WORK_QUEUE_NAME, "work hello!");
    }

    @GetMapping(value = "/pubsub")
    public void pubsub() {
        rabbitTemplate.convertAndSend(RabbitConstant.PUBLISH_SUBSCRIBE_EXCHANGE_NAME, null, "publish/subscribe hello");
    }

    @GetMapping(value = "/routing")
    public void routing() {
        // 给第一个队列发送消息
        rabbitTemplate.convertAndSend(RabbitConstant.ROUTING_EXCHANGE_NAME, RabbitConstant.ROUTING_FIRST_QUEUE_ROUTING_KEY_NAME, "routing hello");
    }

    @GetMapping(value = "/topics")
    public void topics() {
        // 给第一个队列发送消息,此时队列能接受到消息,因为队列通配符为 #.first.#,而 routing_key 为 topics.first.routing.key,匹配成功
        rabbitTemplate.convertAndSend(RabbitConstant.TOPICS_EXCHANGE_NAME, RabbitConstant.TOPICS_FIRST_QUEUE_ROUTING_KEY, "topics hello");
        // 给第二个队列发送消息,此时队列也能接受到消息,因为队列通配符为 *.second.#,而 routing_key 为 topics.second.routing.key,匹配成功
        rabbitTemplate.convertAndSend(RabbitConstant.TOPICS_EXCHANGE_NAME, RabbitConstant.TOPICS_SECOND_QUEUE_ROUTING_KEY, "topics hello");
        // 给第三个队列发送消息,此时队列无法接受到消息,因为队列通配符为 *.third.*,而 routing_key 为 topics.third.routing.key,匹配失败
        rabbitTemplate.convertAndSend(RabbitConstant.TOPICS_EXCHANGE_NAME, RabbitConstant.TOPICS_THIRD_QUEUE_ROUTING_KEY, "topics hello");
    }

    @GetMapping(value = "/header")
    public void header() {
        // 这条消息应该能被两个队列都接收到,第一个队列 all 匹配成功,第二个队列 hello-value any匹配成功
        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setHeader("matchAll", "YES");
        messageProperties.setHeader("hello", "world");
        Message message = new Message("header first hello".getBytes(StandardCharsets.UTF_8), messageProperties);
        rabbitTemplate.convertAndSend(RabbitConstant.HEADER_EXCHANGE_NAME, null, message);

        // 这条消息应该只被第二个队列接受,第一个队列 all 匹配失败,第二个队列 matchAll-NO any匹配成功
        MessageProperties messagePropertiesSecond = new MessageProperties();
        messagePropertiesSecond.setHeader("matchAll", "NO");
        Message messageSecond = new Message("header second hello".getBytes(StandardCharsets.UTF_8), messagePropertiesSecond);
        rabbitTemplate.convertAndSend(RabbitConstant.HEADER_EXCHANGE_NAME, null, messageSecond);
    }

    @GetMapping(value = "/rpc")
    public void rpc() {
        Object responseMsg = rabbitTemplate.convertSendAndReceive(RabbitConstant.RPC_QUEUE_NAME, "rpc hello!");
        System.out.println("rabbit rpc response message: " + responseMsg);
    }

}
SpringBoot RabbitMQ 简单模式
  • 生产者声明队列,并向队列发送消息
import com.example.rabbitmq.constant.RabbitConstant;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitSimpleProvider {

    @Bean
    public Queue simpleQueue() {
        return new Queue(RabbitConstant.SIMPLE_QUEUE_NAME);
    }

}
  • 消费者监听队列,并消费消息
import com.example.rabbitmq.constant.RabbitConstant;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class RabbitSimpleConsumer {

    @RabbitHandler
    @RabbitListener(queues = RabbitConstant.SIMPLE_QUEUE_NAME)
    public void simpleListener(String context) {
        System.out.println("rabbit receiver: " + context);
    }

}
  • 单元测试
@Test
public void simple() {
    rabbitTemplate.convertAndSend(RabbitConstant.SIMPLE_QUEUE_NAME, "hello world!");
}
  • 响应结果

SpringBoot RabbitMQ Work 模式
  • 生产者声明队列,并向队列生产消息
import com.example.rabbitmq.constant.RabbitConstant;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitWorkProvider {

    @Bean
    public Queue workQueue() {
        return new Queue(RabbitConstant.WORK_QUEUE_NAME);
    }

}
  • 消费者监听队列,并消费消息(这里有两个消费者监听同一队列)
import com.example.rabbitmq.constant.RabbitConstant;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class RabbitWorkConsumer {

    @RabbitListener(queues = RabbitConstant.WORK_QUEUE_NAME)
    @RabbitHandler
    public void workQueueListenerFirst(String context) {
        System.out.println("rabbit workQueue listener first receiver: " + context);
    }

    @RabbitListener(queues = RabbitConstant.WORK_QUEUE_NAME)
    @RabbitHandler
    public void workQueueListenerSecond(String context) {
        System.out.println("rabbit workQueue listener second receiver: " + context);
    }

}
  • 单元测试
@Test
public void work() {
    rabbitTemplate.convertAndSend(RabbitConstant.WORK_QUEUE_NAME, "work hello!");
}
  • 响应结果(由于有两个消费者监听同一队列,消息只能被其中一者进行消费,默认是负载均衡的将消息发送给所有消费者)

SpringBoot RabbitMQ 发布/订阅模式
  • 生产者声明两个队列和一个 fanout 交换机,并将这两个队列和交换机进行绑定
  • 交换机种类一共有四种 fanout、direct、topic、header(文末介绍)
import com.example.rabbitmq.constant.RabbitConstant;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitPublishSubscribeProvider {

    @Bean
    public Queue pubsubQueueFirst() {
        return new Queue(RabbitConstant.PUBLISH_SUBSCRIBE_FIRST_QUEUE_NAME);
    }

    @Bean
    public Queue pubsubQueueSecond() {
        return new Queue(RabbitConstant.PUBLISH_SUBSCRIBE_SECOND_QUEUE_NAME);
    }

    @Bean
    public FanoutExchange fanoutExchange() {
        // 创建fanout类型交换机,表示与此交换机会将消息发送给所有绑定的队列
        return new FanoutExchange(RabbitConstant.PUBLISH_SUBSCRIBE_EXCHANGE_NAME);
    }

    @Bean
    public Binding pubsubQueueFirstBindFanoutExchange() {
        // 队列一绑定交换机
        return BindingBuilder.bind(pubsubQueueFirst()).to(fanoutExchange());
    }

    @Bean
    public Binding pubsubQueueSecondBindFanoutExchange() {
        // 队列二绑定交换机
        return BindingBuilder.bind(pubsubQueueSecond()).to(fanoutExchange());
    }

}
  • 消费者监听队列,并进行消费
import com.example.rabbitmq.constant.RabbitConstant;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class RabbitPublishSubscribeConsumer {

    @RabbitListener(queues = RabbitConstant.PUBLISH_SUBSCRIBE_FIRST_QUEUE_NAME)
    @RabbitHandler
    public void pubsubQueueFirst(String context) {
        System.out.println("rabbit pubsub queue first receiver: " + context);
    }

    @RabbitListener(queues = RabbitConstant.PUBLISH_SUBSCRIBE_SECOND_QUEUE_NAME)
    @RabbitHandler
    public void pubsubQueueSecond(String context) {
        System.out.println("rabbit pubsub queue second receiver: " + context);
    }

}
  • 单元测试
@Test
public void pubsub() {
    rabbitTemplate.convertAndSend(RabbitConstant.PUBLISH_SUBSCRIBE_EXCHANGE_NAME, null, "publish/subscribe hello");
}
  • 响应结果

SpringBoot RabbitMQ 路由模式
  • 生产者声明三个队列和一个 direct 交换机,将这三个队列和交换机进行绑定并设定交换机与队列之间的路由
import com.example.rabbitmq.constant.RabbitConstant;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitRoutingProvider {

    @Bean
    public Queue rabbitRoutingFirstQueue() {
        return new Queue(RabbitConstant.ROUTING_FIRST_QUEUE_NAME);
    }

    @Bean
    public Queue rabbitRoutingSecondQueue() {
        return new Queue(RabbitConstant.ROUTING_SECOND_QUEUE_NAME);
    }

    @Bean
    public Queue rabbitRoutingThirdQueue() {
        return new Queue(RabbitConstant.ROUTING_THIRD_QUEUE_NAME);
    }

    @Bean
    public DirectExchange directExchange() {
        // 创建direct类型交换机,表示与此交换机会将消息发送给 routing_key 完全相同的队列
        return new DirectExchange(RabbitConstant.ROUTING_EXCHANGE_NAME);
    }

    @Bean
    public Binding routingFirstQueueBindDirectExchange() {
        // 队列一绑定direct交换机,并设置 routing_key 为 routing_first_queue_routing_key
        return BindingBuilder.bind(rabbitRoutingFirstQueue()).to(directExchange()).with(RabbitConstant.ROUTING_FIRST_QUEUE_ROUTING_KEY_NAME);
    }

    @Bean
    public Binding routingSecondQueueBindDirectExchange() {
        // 队列二绑定direct交换机,并设置 routing_key 为 routing_second_queue_routing_key
        return BindingBuilder.bind(rabbitRoutingSecondQueue()).to(directExchange()).with(RabbitConstant.ROUTING_SECOND_QUEUE_ROUTING_KEY_NAME);
    }

    @Bean
    public Binding routingThirdQueueBindDirectExchange() {
        // 队列三绑定direct交换机,并设置 routing_key 为 routing_third_queue_routing_key
        return BindingBuilder.bind(rabbitRoutingThirdQueue()).to(directExchange()).with(RabbitConstant.ROUTING_THIRD_QUEUE_ROUTING_KEY_NAME);
    }

}
  • 消费者监听队列,并进行消费
import com.example.rabbitmq.constant.RabbitConstant;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class RabbitRoutingConsumer {

    @RabbitListener(queues = RabbitConstant.ROUTING_FIRST_QUEUE_NAME)
    @RabbitHandler
    public void routingFirstQueueListener(String context) {
        System.out.println("rabbit routing queue first receiver: " + context);
    }

    @RabbitListener(queues = RabbitConstant.ROUTING_SECOND_QUEUE_NAME)
    @RabbitHandler
    public void routingSecondQueueListener(String context) {
        System.out.println("rabbit pubsub queue second receiver: " + context);
    }

    @RabbitListener(queues = RabbitConstant.ROUTING_THIRD_QUEUE_NAME)
    @RabbitHandler
    public void routingThirdQueueListener(String context) {
        System.out.println("rabbit pubsub queue third receiver: " + context);
    }

}
  • 单元测试
@Test
public void routing() {
    // 给第一个队列发送消息
    rabbitTemplate.convertAndSend(RabbitConstant.ROUTING_EXCHANGE_NAME, RabbitConstant.ROUTING_FIRST_QUEUE_ROUTING_KEY_NAME, "routing hello");
}
  • 响应结果

SpringBoot RabbitMQ 主题模式
  • 生产者声明三个队列和一个 topic 交换机,队列分别与 topic 交换机绑定并设置 routing key 统配符,若 routing key 满足交换机与队列间通配符要求则将消息存储至队列
  • \# 通配符可以匹配一个或多个单词,* 通配符可以匹配一个单词;假如交换机(Exchange)与队列之间的 routing key 通配符为 #.hello.#,则代表 routing key 中间带有 hello 单词的都满足条件,消息将存储至队列
import com.example.rabbitmq.constant.RabbitConstant;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitTopicProvider {

    @Bean
    public Queue topicFirstQueue() {
        return new Queue(RabbitConstant.TOPICS_FIRST_QUEUE_NAME);
    }

    @Bean
    public Queue topicSecondQueue() {
        return new Queue(RabbitConstant.TOPICS_SECOND_QUEUE_NAME);
    }

    @Bean
    public Queue topicThirdQueue() {
        return new Queue(RabbitConstant.TOPICS_THIRD_QUEUE_NAME);
    }

    @Bean
    public TopicExchange topicExchange() {
        // 创建topic类型交换机,表示与此交换机会将消息发送给 routing_key 通配符匹配成功的队列
        return new TopicExchange(RabbitConstant.TOPICS_EXCHANGE_NAME);
    }

    @Bean
    public Binding topicFirstQueueBindExchange() {
        // 队列一绑定topic类型交换机,并设置 routing_key 通配符为 #.first.#
        return BindingBuilder.bind(topicFirstQueue()).to(topicExchange()).with(RabbitConstant.TOPICS_ROUTING_KEY_FIRST_WILDCARD);
    }

    @Bean
    public Binding topicSecondQueueBindExchange() {
        // 队列二绑定topic类型交换机,并设置 routing_key 通配符为 *.second.#
        return BindingBuilder.bind(topicSecondQueue()).to(topicExchange()).with(RabbitConstant.TOPICS_ROUTING_KEY_SECOND_WILDCARD);
    }

    @Bean
    public Binding topicThirdQueueBindExchange() {
        // 队列三绑定topic类型交换机,并设置 routing_key 通配符为 *.third.*
        return BindingBuilder.bind(topicThirdQueue()).to(topicExchange()).with(RabbitConstant.TOPICS_ROUTING_KEY_THRID_WILDCARD);
    }

}
  • 消费者监听队列,并进行消费
import com.example.rabbitmq.constant.RabbitConstant;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class RabbitTopicsConsumer {

    @RabbitListener(queues = RabbitConstant.TOPICS_FIRST_QUEUE_NAME)
    @RabbitHandler
    public void topicFirstQueue(String context) {
        System.out.println("rabbit topics queue first receiver: " + context);
    }

    @RabbitListener(queues = RabbitConstant.TOPICS_SECOND_QUEUE_NAME)
    @RabbitHandler
    public void topicSecondQueue(String context) {
        System.out.println("rabbit topics queue second receiver: " + context);
    }

    @RabbitListener(queues = RabbitConstant.TOPICS_THIRD_QUEUE_NAME)
    @RabbitHandler
    public void topicThirdQueue(String context) {
        System.out.println("rabbit topics queue third receiver: " + context);
    }

}
  • 单元测试
@Test
public void topics() {
    // 给第一个队列发送消息,此时队列能接受到消息,因为队列通配符为 #.first.#,而 routing_key 为 topics.first.routing.key,匹配成功
    rabbitTemplate.convertAndSend(RabbitConstant.TOPICS_EXCHANGE_NAME, RabbitConstant.TOPICS_FIRST_QUEUE_ROUTING_KEY, "topics hello");
    // 给第二个队列发送消息,此时队列也能接受到消息,因为队列通配符为 *.second.#,而 routing_key 为 topics.second.routing.key,匹配成功
    rabbitTemplate.convertAndSend(RabbitConstant.TOPICS_EXCHANGE_NAME, RabbitConstant.TOPICS_SECOND_QUEUE_ROUTING_KEY, "topics hello");
    // 给第三个队列发送消息,此时队列无法接受到消息,因为队列通配符为 *.third.*,而 routing_key 为 topics.third.routing.key,匹配失败
    rabbitTemplate.convertAndSend(RabbitConstant.TOPICS_EXCHANGE_NAME, RabbitConstant.TOPICS_THIRD_QUEUE_ROUTING_KEY, "topics hello");
    }
  • 响应结果

SpringBoot RabbitMQ header模式
  • 生产者声明队列并创建 HeaderExchange 交换机,将队列分别与交换机通过 header 进行绑定
import com.example.rabbitmq.constant.RabbitConstant;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.HeadersExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class RabbitHeaderProvider {

    @Bean
    public Queue headerFirstQueue() {
        return new Queue(RabbitConstant.HEADER_FIRST_QUEUE_NAME);
    }

    @Bean
    public Queue headerSecondQueue() {
        return new Queue(RabbitConstant.HEADER_SECOND_QUEUE_NAME);
    }

    @Bean
    public HeadersExchange headersExchange() {
        return new HeadersExchange(RabbitConstant.HEADER_EXCHANGE_NAME);
    }

    @Bean
    public Binding headerFirstQueueBindExchange() {
        Map<String, Object> headersMap = new HashMap<>(8);
        headersMap.put("matchAll", "YES");
        headersMap.put("hello", "world");

        return BindingBuilder.bind(headerFirstQueue()).to(headersExchange()).whereAll(headersMap).match();
    }

    @Bean
    public Binding headerSecondQueueBindExchange() {
        Map<String, Object> headersMap = new HashMap<>(8);
        headersMap.put("matchAll", "NO");
        headersMap.put("hello", "world");

        return BindingBuilder.bind(headerSecondQueue()).to(headersExchange()).whereAny(headersMap).match();
    }

}
  • 交换机与队列绑定详情

  • 消费者监听队列,并进行消费
import com.example.rabbitmq.constant.RabbitConstant;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class RabbitHeaderConsumer {

    @RabbitListener(queues = RabbitConstant.HEADER_FIRST_QUEUE_NAME)
    @RabbitHandler
    public void headerFirstQueue(String context) {
        System.out.println("rabbit header queue first receiver: " + context);
    }

    @RabbitListener(queues = RabbitConstant.HEADER_SECOND_QUEUE_NAME)
    @RabbitHandler
    public void headerSecondQueue(String context) {
        System.out.println("rabbit header queue second receiver: " + context);
    }

}
  • 单元测试
@Test
public void header() {
    // 这条消息应该能被两个队列都接收到,第一个队列 all 匹配成功,第二个队列 hello-value any匹配成功
    MessageProperties messageProperties = new MessageProperties();
    messageProperties.setHeader("matchAll", "YES");
    messageProperties.setHeader("hello", "world");
    Message message = new Message("header first hello".getBytes(StandardCharsets.UTF_8), messageProperties);
    rabbitTemplate.convertAndSend(RabbitConstant.HEADER_EXCHANGE_NAME, null, message);

    // 这条消息应该只被第二个队列接受,第一个队列 all 匹配失败,第二个队列 matchAll-NO any匹配成功
    MessageProperties messagePropertiesSecond = new MessageProperties();
    messagePropertiesSecond.setHeader("matchAll", "NO");
    Message messageSecond = new Message("header second hello".getBytes(StandardCharsets.UTF_8), messagePropertiesSecond);
    rabbitTemplate.convertAndSend(RabbitConstant.HEADER_EXCHANGE_NAME, null, messageSecond);
}
  • 响应结果

SpringBoot RabbitMQ RPC模式
  • 生产者声明队列
import com.example.rabbitmq.constant.RabbitConstant;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RabbitRpcProvider {

    @Bean
    public Queue rpcQueue() {
        return new Queue(RabbitConstant.RPC_QUEUE_NAME);
    }

}
  • 消费者监听队列,并进行消费
import com.example.rabbitmq.constant.RabbitConstant;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class RabbitRpcConsumer {

    @RabbitListener(queues = RabbitConstant.RPC_QUEUE_NAME)
    @RabbitHandler
    public String rpcQueue(String context) {
        System.out.println("rabbit rpc queue receiver: " + context);
        return "copy that!";
    }

}
  • 单元测试
@Test
public void rpc() {
    Object responseMsg = rabbitTemplate.convertSendAndReceive(RabbitConstant.RPC_QUEUE_NAME, "rpc hello!");
    System.out.println("rabbit rpc response message: " + responseMsg);
}
  • 响应结果

Exchange 交换机

  • fanout 交换机:通过fanout交换机发送消息,则与fanout交换机绑定的所有队列都能接收到该消息

  • direct 交换机:通过direct交换机发送消息,则与direct交换机绑定队列中routing key完全一致的队列能接收到消息

  • topic 交换机:通过topic交换机发送消息,则与topic交换机绑定队列中routing key经过通配符匹配成功的队列能接收到消息

文章还有很多不足之处,欢迎各位兄弟姐妹批评指正,代码仓库已存放至gitee [SpringBoot RabbitMQ 工作模式仓库链接](https://gitee.com/BarryMan/spring-boot-rabbitmq.git)


gz99rehu
4 声望0 粉丝