RabbitMQ在Springboot使用方法

一、MQ简介#

官网连接 :https://www.rabbitmq.com/documentation.html
简介#
大多应用中,可通过消息服务中间件来提升系统异步通信、扩展解耦能力。
消息的发送者和接收者不需要同时与消息队列交互。消息会保存在队列中,知道接收者取回它。

下面是架构图:
在这里插入图片描述

Producer:消息生产者,负责生产和发送消息到Broker;
Broker:消息处理中心,负责消息存储、确认、重试等;
Consumer:消息消费中心,负责从Broker中获取消息并处理。

消息队列-特性

异步性:将耗时的同步任务通过发送消息的方式进行异步处理,减少等待时间。
松耦合:不同系统、服务之间可以通过消息队列进行通信,不用关心彼此的实现细节,数据格式一致。
分布式:为了防止消息堵塞,可以对消费者集群进行横向扩展,避免单点故障,同样队列本身也可以。
可靠性:将接收到的消息落盘,就算服务器重启或者发生故障,恢复之后也能重新加载。

RabbitMQ核心概念#

RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue Protocol)的开源实现。

Message

消息,消息是不具名的,它由消息头和消息体组成
消息头,包括routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等

Publisher

消息的生产者,也是一个向交换器发布消息的客户端应用程序

Exchange

交换器,将生产者消息路由给服务器中的队列
类型有direct(默认),fanout, topic, 和headers,具有不同转发策略

Queue

消息队列,保存消息直到发送给消费者

Binding

绑定,用于消息队列和交换器之间的关联

Connection

网络连接,比如一个TCP连接

Channel

信道,多路复用连接中的一条独立的双向数据流通道。信道是建立在真实的TCP连接内的虚拟连接,AMQP命令都是通过信道发出去的,不管是发布消息、订阅队列还是接收消息,这些动作都是通过信道完成的。因为对于操作系统来说建立和销毁TCP都是非常昂贵的开销,所以引入了信道的概念,以复用一条TCP连接。

Consumer

消息的消费者,表示一个从消息队列中取得消息的客户端应用程序

Virtual Host

虚拟主机,表示一批交换器、消息队列和相关对象。
vhost 是 AMQP 概念的基础,必须在连接时指定
RabbitMQ 默认的 vhost 是 /
Broker

消息队列服务器实体
在这里插入图片描述

二、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 rabbitmq:management

说明:
4369,25672 (Erlang发现&集群端口)
5672,5671(AMQP端口)
15672(web管理后台端口)
61613,61614(STOMP协议端口)
1883,8883(MQTT协议端口)

设置rabbitMQ docker自启动

docker update rabbitmq --restart=always

查看容器命令:

[root@localhost vagrant]# docker ps
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                                                                                                                                       NAMES
1d7e85d6333a        rabbitmq:management   "docker-entrypoint.s…"   3 minutes ago       Up 3 minutes        0.0.0.0:4369->4369/tcp, 0.0.0.0:5671-5672->5671-5672/tcp, 0.0.0.0:15671-15672->15671-15672/tcp, 0.0.0.0:25672->25672/tcp, 15691-15692/tcp   rabbitmq

访问mq网页 端口地址:15672
在这里插入图片描述

三、RabbitMQ消息发送测试#

RabbitMQ提供了四种Exchange模式:fanout,direct,topic,header 。 header模式在实际使用中较少,这里只讨论前三种模式.

fanout 模式#
fanout 模式就是广播模式,消息来了,会发给所有的队列

file

测试广播模式:
先在交换机创建 fanout模式的交换机,命名为 my.fanout.exchange,然后再到队列创建多个队列,再到交换机绑定队列,fanout可以不设置路由key,因为这个是广播模式的,最后发消息测试。

file

队列接收消息:
file

可以看到绑定的队列已经收到消息了。

Direct 模式
Direct 模式就是指定队列模式, 消息来了,只发给指定的 Queue, 其他Queue 都收不到。
file

Topic 模式#
主题模式,注意这里的主题模式,和 ActivityMQ 里的不一样。 ActivityMQ 里的主题,更像是广播模式。
那么这里的主题模式是什么意思呢? 如图所示消息来源有: 美国新闻,美国天气,欧洲新闻,欧洲天气。
如果你想看 美国主题: 那么就会收到 美国新闻,美国天气。
如果你想看 新闻主题: 那么就会收到 美国新闻,欧洲新闻。
如果你想看 天气主题: 那么就会收到 美国天气,欧洲天气。
如果你想看 欧洲主题: 那么就会收到 欧洲新闻,欧洲天气。

这样就可以灵活搭配~

file

管理界面

1.4.1. 添加用户
如果不使用guest,我们也可以自己创建一个用户:

在这里插入图片描述

1、 超级管理员(administrator)

可登陆管理控制台,可查看所有的信息,并且可以对用户,策略(policy)进行操作。

2、 监控者(monitoring)

可登陆管理控制台,同时可以查看rabbitmq节点的相关信息(进程数,内存使用情况,磁盘使用情况等)

3、 策略制定者(policymaker)

可登陆管理控制台, 同时可以对policy进行管理。但无法查看节点的相关信息(上图红框标识的部分)。

4、 普通管理者(management)

仅可登陆管理控制台,无法看到节点信息,也无法对策略进行管理。

5、 其他

无法登陆管理控制台,通常就是普通的生产者和消费者。

1.4.2. 创建Virtual Hosts
虚拟主机:类似于mysql中的database。他们都是以“/”开头

在这里插入图片描述

1.4.3. 设置权限
在这里插入图片描述

1.4.3. 设置权限在这里插入图片描述
创建交换机
在这里插入图片描述
创建队列
在这里插入图片描述
绑定队列
在这里插入图片描述
在这里插入图片描述

SpringBoot正式整和RabbitMQ
1、引入 Spring-boot-starter-amqp
      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>

2、application.yml配置
spring:
  rabbitmq:
    host: 192.168.56.10
    port: 5672
    virtual-host: /

使用步骤:

1、引入amqp场景,RabbitAutotConfiguration就会自动生效
2、给容器中自动配置了RabbitTemplate.AmqpAdmin CachingConnectionFactory、RabbitMessagingTemlate
3、@EnableRabbit

3、测试RabbitMQ
1、AmqpAdmin:管理组件
 /**
     * 创建Exchange
     * 1、如何利用Exchange,Queue,Binding
     *      1、使用AmqpAdmin进行创建
     * 2、如何收发信息
     */
    @Test
    public void contextLoads() {
        //	public DirectExchange(
        //	String name, 交换机的名字
        //	boolean durable, 是否持久
        //	boolean autoDelete, 是否自动删除
        //	Map<String, Object> arguments)
        //	{
        DirectExchange directExchange = new DirectExchange("hello-java.exchange",true,false);
        amqpAdmin.declareExchange(directExchange);
        log.info("Exchange[{}]创建成功:","hello-java.exchange");
    }

    /**
     * 创建队列
     */
    @Test
    public void createQueue() {
        // public Queue(String name, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments) {
        Queue queue = new Queue("hello-java-queue",true,false,false);
        amqpAdmin.declareQueue(queue);
        log.info("Queue[{}]:","创建成功");
    }


/**
     * 绑定队列
     */
    @Test
    public void createBinding() {
        // public Binding(String destination, 目的地
        // DestinationType destinationType, 目的地类型
        // String exchange,交换机
        // String routingKey,//路由键
        Binding binding = new Binding("hello-java-queue",
                Binding.DestinationType.QUEUE,
                "hello-java.exchange",
                "hello.java",null);
        amqpAdmin.declareBinding(binding);
        log.info("Binding[{}]创建成功","hello-java-binding");
    }

2、RabbitTemplate:消息发送处理组件

 @Autowired
    @Test
    public void sendMessageTest() {
        for(int i = 1; i <=5; i++) {
            if(i%2==0) {
                OrderReturnReasonEntity reasonEntity = new OrderReturnReasonEntity();
                reasonEntity.setId(1l);
                reasonEntity.setCreateTime(new java.util.Date());
                reasonEntity.setName("哈哈");
                //
                String msg = "Hello World";
                // 发送的对象类型的消息,可以是一个json
                rabbitTemplate.convertAndSend("hello-java.exchange","hello.java",reasonEntity);
            } else {
                OrderEntity orderEntity = new OrderEntity();
                orderEntity.setOrderSn(UUID.randomUUID().toString());
                rabbitTemplate.convertAndSend("hello-java.exchange","hello.java",orderEntity);
            }
            log.info("消息发送完成{}");
        }

    }

如果需要配置mq消息非序列化,则加入配置文件

@Configuration
public class MyRabbitConfig {
  @Bean
  public MessageConverter messageConverter(){
      return new Jackson2JsonMessageConverter();
  }
}

效果图:
![](https://img-blog.csdnimg.cn/20210116155427913.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21hcmt5aW5nc2hvdQ==,size_16,color_FFFFFF,t_70

13.7 RabbitMQ消息确认机制 - 可靠到达

  • 保证消息不丢失,可靠抵达,可以使用事务消息,性能下降250倍,为此引入确认机制
  • publisher confirmCallback 确认模式
  • publisher returnCallback 未投递到 queue 退回
  • consumer ack 机制

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存失败,源站可能有防盗链机制,建议将图片保存失败,源站可能有防盗链机制,建议将图片保存下来直接上传上传上传(txIwR8xXYZ36-1610783712220)(/image-20201116163631107.png)(/image-20201116163631107.png)(/image-20201116163631107.png)]

可靠抵达 - ConfirmCallback

spring.rabbitmq.publisher-confirms=true

在创建 connectionFactory 的时候设置 PublisherConfirms(true) 选项,开启 confirmcallback

CorrelationData 用来表示当前消息唯一性

消息只要被 broker 接收到就会执行 confirmCallback,如果 cluster 模式,需要所有 broker 接收到才会调用 confirmCallback

被 broker 接收到只能表示 message 已经到达服务器,并不能保证消息一定会被投递到目标 queue 里,所以需要用到接下来的 returnCallback

可靠抵达 - ReturnCallback

spring.rabbitmq.publisher-retuns=true

spring.rabbitmq.template.mandatory=true

confirm 模式只能保证消息到达 broker,不能保证消息准确投递到目标 queue 里。在有些模式业务场景下,我们需要保证消息一定要投递到目标 queue 里,此时就需要用到 return 退回模式

这样如果未能投递到目标 queue 里将调用 returnCallback,可以记录下详细到投递数据,定期的巡检或者自动纠错都需要这些数据

可靠抵达 - Ack 消息确认机制
  • 消费者获取到消息,成功处理,可以回复Ack给Broker
    • basic.ack 用于肯定确认:broker 将移除此消息
    • basic.nack 用于否定确认:可以指定 beoker 是否丢弃此消息,可以批量
    • basic.reject用于否定确认,同上,但不能批量
  • 默认,消息被消费者收到,就会从broker的queue中移除
  • 消费者收到消息,默认自动ack,但是如果无法确定此消息是否被处理完成,或者成功处理,我们可以开启手动ack模式
    • 消息处理成功,ack(),接受下一条消息,此消息broker就会移除
    • 消息处理失败,nack()/reject() 重新发送给其他人进行处理,或者容错处理后ack
    • 消息一直没有调用ack/nack方法,brocker认为此消息正在被处理,不会投递给别人,此时客户端断开,消息不会被broker移除,会投递给别人
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值