SpringBoot整合RabbitMq(六种工作模型)

RabbitMq六种消息模型(SpringBoot版)

关于MQ的基本概念:学习MQ之前,你要先懂这些~_略懂Java的博客-CSDN博客

关于MQRabbitMq的安装:Linux安装RabbitMQ详细教程(下载安装及docker安装)_略懂Java的博客-CSDN博客

RabbitMQ简介

RabbitMQ是由erlang语言开发,基于AMQP(Advanced Message Queue 高级消息队列协议)协议实现的消息队列,它是一种应用程序之间的通信方法,消息队列在分布式系统开发中应用非常广泛。RabbitMQ官方地址:http://www.rabbitmq.com

RabbitMQ的工作原理

下图是RabbitMQ的基本结构:

在这里插入图片描述

组成部分说明:

  • Broker:消息队列服务进程,此进程包括两个部分:Exchange和Queue

  • Exchange:消息队列交换机,按一定的规则将消息路由转发到某个队列,对消息进行过虑。

  • Queue:消息队列,存储消息的队列,消息到达队列并转发给指定的

  • Producer:消息生产者,即生产方客户端,生产方客户端将消息发送

  • Consumer:消息消费者,即消费方客户端,接收MQ转发的消息。

生产者发送消息流程:

1、生产者和Broker建立TCP连接。

2、生产者和Broker建立通道。

3、生产者通过通道消息发送给Broker,由Exchange将消息进行转发。

4、Exchange将消息转发到指定的Queue(队列)

消费者接收消息流程:

1、消费者和Broker建立TCP连接

2、消费者和Broker建立通道

3、消费者监听指定的Queue(队列)

4、当有消息到达Queue时Broker默认将消息推送给消费者。

5、消费者接收到消息。

6、ack回复

Rabbit六种消息模型

RabbitMQ提供了6种消息模型,但是第6种其实是RPC,并不是MQ,因此不予学习。那么也就剩下5种。但是其实3、4、5这三种都属于订阅模型,只不过进行路由的方式不同。

在这里插入图片描述

基本消息模型(点对点)

在这里插入图片描述

在上图的模型中,有以下概念:

  • P:生产者,也就是要发送消息的程序

  • C:消费者:消息的接受者,会一直等待消息到来。

  • queue:消息队列,图中红色部分。可以缓存消息;生产者向其中投递消息,消费者从其中取出消息。

新建一个maven工程,添加spring-boot-starter-web、spring-boot-starter-amqp依赖,另外添加一个spring-boot-starter-test依赖方便测试。

 <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
  </dependencies>

application.yml中添加RabbitMQ的配置:

# 服务端口
server:
  port: 8080
# 配置rabbitmq服务
spring:
  rabbitmq:
    username: rabbitmq
    password: rabbitmq
    virtual-host: /
    host:             #服务器公网地址
    port: 5672

定义队列名称

public interface RabbitMqConstants {
   String SMS_QUEUE  = "sms_queue";
   String EMAIL_QUEUE  = "email_queue";
}

定义RabbitConfig配置类 初始化2个队列

@Configuration
public class RabbitMqConfig {

    /**
     * new Queue(QUEUE_EMAIL,true,false,false)
     *  durable="true" 持久化 rabbitmq重启的时候不需要创建新的队列
     *  auto-delete 表示消息队列没有在使用时将被自动删除 默认是false
     * exclusive  表示该消息队列是否只在当前connection生效,默认是false
     * @return
     */
    @Bean
    public Queue simpleSmsQueueInit() {
        return new Queue(RabbitMqConstants.SMS_QUEUE, true);
    }

    /**
     * 初始化邮箱队列
     * @return
     */
    @Bean
    public Queue simpleEmailQueueInit() {
        return new Queue(RabbitMqConstants.EMAIL_QUEUE, true);
    }
}

定义生产者

@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
public class Producer  {
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Test
    public void sent(){
     rabbitTemplate.convertAndSend(RabbitMqConstants.SMS_QUEUE,"Hello world");
    }
}

我们使用@Test方法运行sent方法向SMS_QUEUE队列发送消息

在RabbitMq控制台我们可以看到初始化的2个队列并且SMS_QUEUE队列有一条待消费消息
在这里插入图片描述

点击队列名称在GetMessage下可以看到具体的消息内容

在这里插入图片描述

然后我们编写消费者类并监听SMS_QUEUE队列

我们添加@Commonent注解目的是让该类添加到Spring容器中,在项目启动的时候可以监听队列中的消息。

@Component
public class Consumer {
    @RabbitListener(queues = RabbitMqConstants.SMS_QUEUE)
    public void getMessage(String message){
        System.out.println(message);
    }
}

我们启动springBoot的启动类启动项目发现消息自动消费了

在这里插入图片描述

在这里插入图片描述

工作模式(work)

在这里插入图片描述

work queues与入门程序相比,多了一个消费端,两个消费端共同消费同一个队列中的消息,但是一个消息只能被一个消费者获取。

这个消息模型在Web应用程序中特别有用,可以处理短的HTTP请求窗口中无法处理复杂的任务。

生产者

@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
public class WorkProducer {
    @Autowired
    RabbitTemplate rabbitTemplate;

    @Test
    public void sent(){
        for (int i = 1; i <=6 ; i++) {
            rabbitTemplate.convertAndSend(RabbitMqConstants.EMAIL_QUEUE,"Hello world"+i);
        }
    }
}

消费者

@Component
public class WorkConsumer {

    @RabbitListener(queues = RabbitMqConstants.EMAIL_QUEUE)
    public void getMessage(String message){
        System.out.println("消费者1接收到信息:"+message);
    }

    @RabbitListener(queues = RabbitMqConstants.EMAIL_QUEUE)
    public void getMessageAgain(String message){
        System.out.println("消费者2接收到信息:"+message);
    }
}

在这里插入图片描述

订阅模型分类

  • 一个生产者多个消费者

  • 每个消费者都有一个自己的队列

  • 生产者没有将消息直接发送给队列,而是发送给exchange(交换机、转发器)

  • 每个队列都需要绑定到交换机上

  • 生产者发送的消息,经过交换机到达队列,实现一个消息被多个消费者消费

Exchange类型

  • Fanout:广播,将消息交给所有绑定到交换机的队列

  • Direct:定向,把消息交给符合指定routing key 的队列

  • Topic:通配符,把消息交给符合routing pattern(路由模式) 的队列

广播模型(Fanout)

在这里插入图片描述
首先我们创建2个队列,分别是消息的队列和邮箱队列 创建一个fanout交换机,将这两个队列绑定到交换机上

  public interface RabbitMqConstants {
    String SMS_QUEUE  = "sms_queue";

   String EMAIL_QUEUE  = "email_queue";

   String FANOUT_EXCHANGE = "fanout_exchange";
  }
@Configuration
public class RabbitMqConfig {

    /**
     * new Queue(QUEUE_EMAIL,true,false,false)
     *  durable="true" 持久化 rabbitmq重启的时候不需要创建新的队列
     *  auto-delete 表示消息队列没有在使用时将被自动删除 默认是false
     * exclusive  表示该消息队列是否只在当前connection生效,默认是false
     * @return
     */
    @Bean
    public Queue simpleSmsQueueInit() {
        return new Queue(RabbitMqConstants.SMS_QUEUE, true);
    }

    /**
     * 初始化邮箱队列
     * @return
     */
    @Bean
    public Queue simpleEmailQueueInit() {
        return new Queue(RabbitMqConstants.EMAIL_QUEUE, true);
    }

    /**
     * 初始化fanout交换机
     * @return
     */
    @Bean
    public FanoutExchange fanoutExchangeInit() {
        return new FanoutExchange(RabbitMqConstants.FANOUT_EXCHANGE, true,false);
    }

    /**
     * 短信队列绑定到交换机
     * @param simpleSmsQueueInit
     * @param fanoutExchange
     * @return
     */
    @Bean
    public Binding bindingSmsQueue(Queue simpleSmsQueueInit, FanoutExchange fanoutExchange) {
        return BindingBuilder.bind(simpleSmsQueueInit).to(fanoutExchange);
    }

    /**
     * 邮箱队列绑定到交换机
     * @param simpleEmailQueueInit
     * @param fanoutExchange
     * @return
     */
    @Bean
    public Binding bindingEmailQueue(Queue simpleEmailQueueInit, FanoutExchange fanoutExchange) {
        return BindingBuilder.bind(simpleEmailQueueInit).to(fanoutExchange);
    }

}

生产者

@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
public class FanoutProducer {
    @Autowired
    RabbitTemplate rabbitTemplate;

    @Test
    public void sent(){
        rabbitTemplate.convertAndSend(RabbitMqConstants.FANOUT_EXCHANGE,"","我是交换机发出的消息");
    }
}

消费者

@Component
public class FanoutConsumer {

    @RabbitListener(queues = RabbitMqConstants.SMS_QUEUE)
    public void getMessage(String message){
        System.out.println("短信消费者接收到信息:"+message);
    }

    @RabbitListener(queues = RabbitMqConstants.EMAIL_QUEUE)
    public void getMessageAgain(String message){
        System.out.println("邮箱消费者接收到信息:"+message);
    }
}

在这里插入图片描述

路由模式(direct)

在这里插入图片描述

P:生产者,向Exchange发送消息,发送消息时,会指定一个routing key。

X:Exchange(交换机),接收生产者的消息,然后把消息递交给 与routing key完全匹配的队列

初始化路由交换机

   String SMS_QUEUE  = "sms_queue";

   String EMAIL_QUEUE  = "email_queue";

   String DIRECT_EXCHANGE = "direct_exchange";
@Configuration
public class RabbitMqConfig {
    /**
     * 初始化direct交换机
     * @return
     */
    @Bean
    public DirectExchange directExchangeInit() {
        return new DirectExchange(RabbitMqConstants.DIRECT_EXCHANGE, true,false);
    }

    /**
     * 初始化短信队列
     * @return
     */
    @Bean
    public Queue directSmsQueueInit() {
        return new Queue(RabbitMqConstants.SMS_QUEUE, true);
    }

    /**
     * 初始化邮箱队列
     * @return
     */
    @Bean
    public Queue directEmailQueueInit() {
        return new Queue(RabbitMqConstants.EMAIL_QUEUE, true);
    }

    /**
     * 短信队列绑定到交换机
     * @param directSmsQueueInit
     * @param directExchange
     * @return
     */
    @Bean
    public Binding directBindingSmsQueue(Queue directSmsQueueInit, DirectExchange directExchange) {
        return BindingBuilder.bind(directSmsQueueInit).to(directExchange).with("sms");
    }

    /**
     * 邮箱队列绑定到交换机
     * @param directEmailQueueInit
     * @param directExchange
     * @return
     */
    @Bean
    public Binding directBindingEmailQueue(Queue directEmailQueueInit, DirectExchange directExchange) {
        return BindingBuilder.bind(directEmailQueueInit).to(directExchange).with("email");
    }
}

生产者

@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
public class DirectProducer {
    @Autowired
    RabbitTemplate rabbitTemplate;

    @Test
    public void sent(){
        rabbitTemplate.convertAndSend(RabbitMqConstants.DIRECT_EXCHANGE,"email","我是交换机发出的消息");
    }
}

消费者

@Component
public class DirectConsumer {

    @RabbitListener(queues = RabbitMqConstants.SMS_QUEUE)
    public void getMessage(String message){
        System.out.println("短信消费者接收到信息:"+message);
    }

    @RabbitListener(queues = RabbitMqConstants.EMAIL_QUEUE)
    public void getMessageAgain(String message){
        System.out.println("邮箱消费者接收到信息:"+message);
    }
}

在这里插入图片描述

主题模式(Topic)

在这里插入图片描述

每个消费者监听自己的队列,并且设置带统配符的routingkey,生产者将消息发给broker,由交换机根据routingkey来转发消息到指定的队列。

Routingkey一般都是有一个或者多个单词组成,多个单词之间以“.”分割,例如:inform.sms

通配符规则:

#:匹配一个或多个词

*:匹配不多不少恰好1个词

举例:

sms.#:能够匹配sms.irs.corporate 或者 sms.irs

email.*:只能匹配email.irs

public interface RabbitMqConstants {
   String TOPIC_EXCHANGE = "topic_exchange";

   String SMS_TOPIC_QUEUE = "sms_topic_queue";

   String EMAIL_TOPIC_QUEUE = "email_topic_queue";
}
@Configuration
public class RabbitMqConfig {
    /**
     * 初始化topic交换机
     * @return
     */
    @Bean
    public TopicExchange topicExchangeInit() {
        return new TopicExchange(RabbitMqConstants.TOPIC_EXCHANGE, true,false);
    }

    /**
     * 初始化短信队列
     * @return
     */
    @Bean
    public Queue topicSmsQueueInit() {
        return new Queue(RabbitMqConstants.SMS_TOPIC_QUEUE, true);
    }

    /**
     * 初始化邮箱队列
     * @return
     */
    @Bean
    public Queue topicEmailQueueInit() {
        return new Queue(RabbitMqConstants.EMAIL_TOPIC_QUEUE, true);
    }

    /**
     * 短信队列绑定到交换机
     * @param topicSmsQueueInit
     * @param topicExchangeInit
     * @return
     */
    @Bean
    public Binding topicBindingSmsQueue(Queue topicSmsQueueInit, TopicExchange topicExchangeInit) {
        return BindingBuilder.bind(topicSmsQueueInit).to(topicExchangeInit).with("sms.#");
    }

    /**
     * 邮箱队列绑定到交换机
     * @param topicEmailQueueInit
     * @param topicExchangeInit
     * @return
     */
    @Bean
    public Binding topicBindingEmailQueue(Queue topicEmailQueueInit, TopicExchange topicExchangeInit) {
        return BindingBuilder.bind(topicEmailQueueInit).to(topicExchangeInit).with("email.*");
    }
}

生产者

@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
public class TopicProducer {
    @Autowired
    RabbitTemplate rabbitTemplate;

    @Test
    public void sent(){
        rabbitTemplate.convertAndSend(RabbitMqConstants.TOPIC_EXCHANGE,"sms.x.x","我是主题模式发出的消息1");
        rabbitTemplate.convertAndSend(RabbitMqConstants.TOPIC_EXCHANGE,"email.x","我是主题模式发出的消息2");
    }
}

消费者

@Component
public class TopicConsumer {

    @RabbitListener(queues = RabbitMqConstants.SMS_TOPIC_QUEUE)
    public void getMessage(String message){
        System.out.println("主题模式短信消费者接收到信息:"+message);
    }

    @RabbitListener(queues = RabbitMqConstants.EMAIL_TOPIC_QUEUE)
    public void getMessageAgain(String message){
        System.out.println("主题模式邮箱消费者接收到信息:"+message);
    }
}

[外链图片转存中...(img-bFPMkn3K-1659596315509)]

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值