rabbitMq 环境搭建 及 与 springboot 集成(完整提供了所有业务场景demo)

目录

1.基础知识:

1.0 前言:

 1.1 rabbitmq的用户角色

1.2 rabbitmq的端口号

1.3 消息队列的运行原理

1.4你必须知道的Rabbit

2.六种队列

2.1 上图1:  简单队列   

2.2 上图2:Work模式 

2.3上图3: 订阅模式  Fanout Exchange

2.4上图4: 路由模式 Direct Exchange

2.5 上图5:主题模式 Topic Exchange (通配符模式)

3.应用场景

3.1.延迟队列

3.2.消息错峰

3.3.消息分发

3.4.应用解耦

3.5.消息确认ACK

4.rabbitMq与Erlang版本对应关系

5.windows搭建

5.1安装Erlang

5.1.1下载erlang

5.1.2安装erlang

5.2安装rabbitmq

5.2.1下载rabbitmq

5.2.2安装Rabbitmq

5.2.3 启用管理工具

6.linux搭建

6.1 说明:

6.2CentOs6安装:

6.2.1下载安装包:

6.2.2centos6安装:

6.3 centos7安装:

6.4 浏览器访问

6.5 移除queue

7.与spingboot集成

7.1.配置rabbitmq连接信息:

7.2 添加AMQP支持

7.3定制化AMQP模板

7.4 direct类型 

7.4.1定义direct类型队列、交换机并绑定:

7.4.2 controller中发送消息

7.4.3 receiver端接收消息

7.5 fanout类型 

7.5.1定义fanout类型队列、交换机并绑定:

7.5.2 controller中发送消息

7.5.3 receiver端接收消息

7.6 diedletter类型(延迟消费类型)

7.6.1定义diedletter类型队列、交换机并绑定:

7.6.2 controller中发送消息

7.6.3 receiver端接收消息

7.7 topic类型

7.7.1定义topic类型队列、交换机并绑定:

7.7.2 controller中发送消息

7.7.3 receiver端接收消息

8.上代码


1.基础知识:

1.0 前言:

RabbitMQ是一个由erlang语言开发的基于AMQP(Advanved Message Queue)队列协议的开源实现。

支持的操作系统  linux、windows、macox等

支持的开发语言 java、python、ruby、.net、php、c/c++、node.js等

官网 https://www.rabbitmq.com/

 1.1 rabbitmq的用户角色

           1、 超级管理员(administrator)

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

           2、 监控者(monitoring)

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

           3、 策略制定者(policymaker)

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

           4、 普通管理者(management)

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

           5、 其他

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

1.2 rabbitmq的端口号

               5672: AMQP协议的端口号(与Java交互)

               15672: 管理工具的端口

               25672: 集群

这些端口需要防火墙放行,详细的操作细节后面的linux、windows搭建会有提及

1.3 消息队列的运行原理

从上图可以看出、生产者、消息队列、消费者是最重要的三个概念:

    生产者(Producer):创建消息到消息队列中(消息的创建者,负责创建和推送数据到消息服务器)。

    消息队列(Queue):存储消息。

    消费者(Consumer):监听指定消息队列,当消息队列接收到消息后,获取消息并处理。

    RabbitMQ:创建消息队列,并提供API给生产者和消费者进行存取消息,用于扮演“快递”的角色,本身不生产消息,只是扮演“快递”的角色。

    生产者产生消息并调用RabbitMQ的API将消息加入到对应的消息队列中,消费者通过RabbitMQ的API从消息队列中获取消息进行消费。

这里面有一个虚拟机的概念,你可以把它理解为域名,在应用中需要通过配置或者代码指定你要用哪个虚拟机(Vhost)。如果你不指定,那么默认的会选用 "/".前提是你的当前用户有对这个虚拟机 "/" 的使用权限。虚拟机可以在rabbitmq的可视化页面里面配置。

1.4你必须知道的Rabbit

 想要真正的了解Rabbit有些名词是你必须知道的。

           包括:ConnectionFactory(连接管理器)、Channel(信道)、Exchange(交换器)、Queue(队列)、            RoutingKey(路由键)、BindingKey(绑定键)。

           ConnectionFactory(连接管理器):应用程序与Rabbit之间建立连接的管理器,程序代码中使用;

           Channel(信道):消息推送使用的通道;

           Exchange(交换器):用于接受、分配消息;

           Queue(队列):用于存储生产者的消息;

           RoutingKey(路由键):用于把生成者的数据分配到交换器上;

           BindingKey(绑定键):用于把交换器的消息绑定到队列上;

2.六种队列

rabbitmq一共有六种队列,其中RPC已被淘汰:

2.1 上图1:  简单队列   

生产者与消费者一一对应 生产者将消息发送到队列,消费者从队列中获取消息。

在这种模式下一个生产者对应了多个消费者,但是一个消息只能被一个消费者获取。可以配置消息分发到消费者的路由规则

 “P”是我们的生产者,“C”是我们的消费者。中间的框是一个队列。

  生产者将消息发送到队列,消费者从队列中消费。

2.2 上图2:Work模式 

一个生产者多个消费者,每个消费者获取到的消息唯一

2.3上图3: 订阅模式  Fanout Exchange

解读:
1、1个生产者,多个消费者
2、每一个消费者都有自己的一个队列
3、生产者没有将消息直接发送到队列,而是发送到了交换机
4、每个队列都要绑定到交换机
5、生产者发送的消息,经过交换机,到达队列,实现,一个消息被多个消费者获取的目的
注意:一个消费者队列可以有多个消费者实例,只有其中一个消费者实例会消费

fanout(不处理路由键):每个和交换机绑定的队列都会收到消息

2.4上图4: 路由模式 Direct Exchange

发送消息到交换机并且要指定路由key ,消费者将队列绑定到交换机时需要指定路由key。它会把消息路由到那些binding key与routing key完全匹配的Queue中。

2.5 上图5:主题模式 Topic Exchange (通配符模式)

这个可以理解为队列的模糊匹配。消息经过交换机推送到符合通配符规则的队列中。

将路由键和某模式进行匹配,此时队列需要绑定在一个模式上,“#”匹配一个词或多个词,“*”只匹配一个词。当消息发送至交换机时,只有routingKey能够满足通配规则的队列才能够接收到消息。

例如:routingKey 为   testqueue  的队列 能够接收到  test#  的消息

 

 

3.应用场景

3.1.延迟队列

   用户注册后长时间不活跃定时推送提醒

   订单下单后长时间未支付转至推送提醒

   延迟重试,比如服务原因导致业务执行终端通过延迟重试保障业务完整性等

3.2.消息错峰

   秒杀、促销等大流量信息短时间注入是的错峰处理以平衡上下游吞吐量

3.3.消息分发

    统一消息源发送的消息应对不同的消费逻辑。如业务处理和日志采集

3.4.应用解耦

   通过发布订阅方式代替接口调用解耦项目

3.5.消息确认ACK

   保障业务完整性  提供了confirm 和 return 两种消息确认回调方法。

   当消息由生产端成功发送至交换机 confirm回调方法会收到布尔类型的ack确认。true为推送至交换机成功。

   当消息由交换机根据routingKey推送至queue队列中时,return回调方法会收到字符类型的replyText确认。

 

4.rabbitMq与Erlang版本对应关系

在搭建RabbitMQ环境过程中,由于版本问题导致环境一直搭建不起来,以下是RabbitMQ与Erlang的版本对应关系

RabbitMQ版本

Erlang最低要求

Erlang最高要求

3.7.7 - 3.7.12

20.3.x

21.x

3.7.0 - 3.7.6

19.3

20.3.x

 

 

5.windows搭建

5.1安装Erlang

5.1.1下载erlang

下载:http://www.erlang.org/download/otp_win64_17.3.exe

 百度云盘下载:https://pan.baidu.com/s/1-5yJGzOl23BuQl1D2_n3SA

5.1.2安装erlang

安装完成。

5.2安装rabbitmq

5.2.1下载rabbitmq

官方下载地址:http://www.rabbitmq.com/download.html

百度云盘下载: https://pan.baidu.com/s/18Dxi01D0sbjPZq-RWymnww

5.2.2安装Rabbitmq

安装完成。

5.2.3 启用管理工具

cmd进入安装目录sbin文件夹下 输入命令:

  启用管理页面命令    rabbitmq-plugins enable rabbitmq_management

在浏览器中输入地址查看:http://127.0.0.1:15672/

使用默认子账号登录:guest    密码  guest

操作界面不再赘述。 至此  windows 环境搭建已全部完成。

6.linux搭建

6.1 说明:

   搭建过程中遇到了mq包与linux系统版本冲突问题,故在此提供了 基于centos6 和centos7两个版本系统的搭建步骤。

6.2CentOs6安装:

6.2.1下载安装包:

rabbitmq安装包:https://pan.baidu.com/s/1pAkK81dFFojnO6fTIxhHkw

erlang安装包:https://pan.baidu.com/s/1jWl-YUSSv1GBUJntZNgXDw

socat安装包:https://pan.baidu.com/s/1DfbX4a4dxtBFA3ZQ7NYDBQ

6.2.2centos6安装:

1.安装erlang的rpm库。

rpm -ivh erlang-20.3.8.7-1.el6.x86_64.rpm

判断erlang是否安装成功:命令行输入   erl 

有输出即表示安装成功

2.安装socat依赖:

安装socat的rpm库。

yum install tcp_wrappers

rpm -ivh socat-1.7.3.0-1.el6.x86_64.rpm(不同版本号要修改)

3.安装RabbitMQ

rpm -ivh rabbitmq-server-3.7.7-1.el6.noarch.rpm (不同版本号要修改)

4.启动rabbitmq:service rabbitmq-server start/stop/restart

5.查看rabbitmq的启动状态 service rabbitmq-server status

6.RabbitMQ配置   这里主要是创建用户和赋权,因为guest这个用户 默认的只能本机访问,而我们部署时一般不会放在同一台机器上。创建了admin用户后就可以去浏览器设置其他用户了。

启动RabbitMQ后执行:

1、rabbitmqctl add_user admin 123456(创建用户)

2、rabbitmqctl set_user_tags admin administrator(将创建好的用户加入管理员)

3、rabbitmqctl set_permissions -p "/" admin "." "." ".*"(授权)

4、rabbitmq-plugins enable rabbitmq_management 启动RabbitMQ管理页面(执行完这个才能用浏览器可视化网页)

5、重启MQ服务   service rabbitmq-server restart

6、开放5672/15672/25672端口。      

vi /etc/sysconfig/iptables

在红框处的下一行依次添加开放端口语句后保存:

-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 5672-j ACCEPT

 

-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 15672-j ACCEPT

 

-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 25672-j ACCEPT

 

重启防火墙: 

service iptables restart

7、在浏览器输入ip:15672后出现RabbitMQ管理台。

6.3 centos7安装:

方式一:  rpm包安装

 1.1. 安装依赖环境Erlang

使用Erlang Solutions源进行安装

# 下载rpm包

wget https://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm

# 从erlang-solutions中更新该包,并将erlang_solutions.repo添加到/etc/yum.repos.d

rpm -Uvh erlang-solutions-1.0-1.noarch.rpm

# 安装

yum install erlang

该包还需依赖到epel源,请确保已有该源,若没有则可通过以下方式安装:

wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

rpm -ivh epel-release-latest-7.noarch.rpm

yum repolist # 查看安装是否成功

 

 

由于Erlang Solutions会进行不断地更新,且RabbitMQ对Erlang的版本有一定的要求(官方版本要求对应表)。所以官方建议我们禁止Erlang版本的自动更新。方法如下:参考如何禁止某个软件包的自动升级

 

# 安装yum-versionlock

yum install yum-plugin-versionlock

# 禁止Erlang自动更新

yum versionlock erlang

 1.2. 安装RabbitMQ Server

从官网下载rpm包并上传到服务器上。官方下载链接

 

# 导入签名

rpm --import https://dl.bintray.com/rabbitmq/Keys/rabbitmq-release-signing-key.asc

# 或

rpm --import https://www.rabbitmq.com/rabbitmq-release-signing-key.asc

# 安装

yum install rabbitmq-server-3.7.7-1.el7.noarch.rpm

 

 

 

 

方式二:  使用脚本安装

 

 

2.1安装erlang

#创建erlang.repo库

curl -s https://packagecloud.io/install/repositories/rabbitmq/erlang/script.rpm.sh | sudo bash

#安装

yum install erlang

2.2安装rabbitmq

#创建rabbitmq-server.repo库

curl -s https://packagecloud.io/install/repositories/rabbitmq/rabbitmq-server/script.rpm.sh | sudo bash

#安装

yum install rabbitmq-server

这种方式虽然会简单点,但我尝试过,发现只有翻墙才能安装成功,所以不太推荐大家使用这种方法。

 

2.3. 启动RabbitMQ Server

# 设置开启启动

chkconfig rabbitmq-server on

 

# 启动服务

service rabbitmq-server start

 

#停止服务

service rabbitmq-server stop

 

#监测状态

service rabbitmq-server status

#用户赋权

rabbitmqctl add_user admin 123456(创建用户)

rabbitmqctl set_user_tags admin administrator(将创建好的用户加入管理员)

rabbitmqctl set_permissions -p "/" admin "." "." ".*"(授权)

2.4. 配置RabbitMQ

2.4.1 找到配置文件

/usr/share/doc/rabbitmq-server-3.7.7/ 目录下复制一份模板到 /etc/rabbitmq 目录下进行修改

 

cd /usr/share/doc/rabbitmq-server-3.7.7/

 

cp rabbitmq.config.example /etc/rabbitmq/rabbitmq.config

 

 

2.4.2 开启管理后台 centos7 防火墙 叫firewall了  不是iptables了啊 ,这个注意下。

rabbitmq-plugins enable rabbitmq_management

# 开放端口

firewall-cmd --add-port=5672/tcp --permanen

firewall-cmd --add-port=15672/tcp --permanen

firewall-cmd --add-port=25672/tcp --permanent

firewall-cmd --reload

 

 

6.4 浏览器访问

 http://ip:15672 ,进入如下页面就证明插件启动成功了

6.5 移除queue

清除的命令是: rabbitmqctl reset

但是在使用此命令前,要先关闭应用,否则不能清除。

关闭应用的命令为: rabbitmqctl stop_app

执行了这两条命令后再次启动此应用。

命令为: rabbitmqctl start_app

再次执行命令: rabbitmqctl list_queues

这次可以看到 listing 及 queues都是空的

 

 

 

 

 

 

 

 

7.与spingboot集成

7.1.配置rabbitmq连接信息:

application.properties中配置rabbitMQ的连接信息:

#对于rabbitMQ的支持
spring.rabbitmq.host=192.168.189.136
spring.rabbitmq.port=5672
spring.rabbitmq.username=yolly
spring.rabbitmq.password=yolly
spring.rabbitmq.virtualHost=yolly
spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.publisher-returns=true
spring.rabbitmq.template.mandatory=true

#并发消费者的初始化值,并发消费者的最大值,每个消费者每次监听时可拉取处理的消息数量。
spring.rabbitmq.listener.concurrency=10
spring.rabbitmq.listener.max-concurrency=20
spring.rabbitmq.listener.prefetch=5

host、用户名、密码还有虚拟机名称这三个需要改成你自己的rabbitmq主机ip和账号密码虚拟机哈。

这个虚拟机spring.rabbitmq.virtualHost可以不写,如果不写或者写“” 他会选择使用 “/” 虚拟机,前提是你的当前账号有 “/” 虚拟机的使用权限。

7.2 添加AMQP支持

因为rabbitmq是基于amqp协议开发的  所以需要在pom.xml中添加amqp dependencies:

同时用到了web测试效果,所以需要引用web starter

<!--amqp-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>RELEASE</version>
</dependency>

7.3定制化AMQP模板

上面我们提到了rabbitmq的消息ack机制,在boot工程中这个机制生效的前提是声明confirm和return为true ,且实现他们的回调方法:

    /**
     * 定制化amqp模版      可根据需要定制多个
     * <p>
     * <p>
     * 此处为模版类定义 Jackson消息转换器
     * ConfirmCallback接口用于实现消息发送到RabbitMQ交换器后接收ack回调   即消息发送到exchange  ack
     * ReturnCallback接口用于实现消息发送到RabbitMQ 交换器,但无相应队列与交换器绑定时的回调  即消息发送不到任何一个队列中  ack
     *
     * @return the amqp template
     */
//    @Primary
    @Bean
    public AmqpTemplate amqpTemplate() {
        Logger log = LoggerFactory.getLogger(RabbitTemplate.class);
//          使用jackson 消息转换器
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        rabbitTemplate.setEncoding("UTF-8");
//        开启returncallback     yml 需要 配置    publisher-returns: true
        rabbitTemplate.setMandatory(true);
        rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
            String correlationId = message.getMessageProperties().getCorrelationId();
            log.debug("消息:{} 发送失败, 应答码:{} 原因:{} 交换机: {}  路由键: {}", correlationId, replyCode, replyText, exchange, routingKey);
        });
        //        消息确认  yml 需要配置   publisher-returns: true
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (ack) {
                log.debug("消息发送到exchange成功,id: {}", correlationData.getId());
            } else {
                log.debug("消息发送到exchange失败,原因: {}", cause);
            }
        });
        return rabbitTemplate;
    }

至此集成工作已经全部实现完毕了

 

7.4 direct类型 

重定向模式 发送至exchange下满足规则的queue

7.4.1定义direct类型队列、交换机并绑定:

  /* ----------------------------------------------------------------------------Direct exchange test--------------------------------------------------------------------------- */

    /**
     * 声明直连交换机 支持持久化.
     *
     * @return the exchange
     */
    @Bean("directExchange")
    public Exchange directExchange() {
        return ExchangeBuilder.directExchange("DIRECT_EXCHANGE").durable(true).build();
    }

    /**
     * 声明一个队列 支持持久化.
     *
     * @return the queue
     */
    @Bean("directQueueA")
    public Queue directQueueA() {
        return QueueBuilder.durable("DIRECT_QUEUE_A").build();
    }
    /**
     * 声明一个队列 支持持久化.
     *
     * @return the queue
     */
    @Bean("directQueueB")
    public Queue directQueueB() {
        return QueueBuilder.durable("DIRECT_QUEUE_B").build();
    }

    /**
     * 通过绑定键 将指定队列绑定到一个指定的交换机 .
     *
     * @param queue    the queue
     * @param exchange the exchange
     * @return the binding
     */
    @Bean
    public Binding directBindingA(@Qualifier("directQueueA") Queue queue, @Qualifier("directExchange") Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with("DIRECT_ROUTING_KEY_A").noargs();
    }
    /**
     * 通过绑定键 将指定队列绑定到一个指定的交换机 .
     *
     * @param queue    the queue
     * @param exchange the exchange
     * @return the binding
     */
    @Bean
    public Binding directBindingB(@Qualifier("directQueueB") Queue queue, @Qualifier("directExchange") Exchange exchange) {
        return BindingBuilder.bind(queue).to(exchange).with("DIRECT_ROUTING_KEY_B").noargs();
    }

7.4.2 controller中发送消息

    /**
     * 测试Direct模式.
     *direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routing key完全匹配的Queue中
     * @param p the p
     * @return the response entity
     */
    @RequestMapping("/direct")
    public ResponseEntity direct(String p) {
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        //routing key为一个句点号“. ”分隔的字符串(我们将被句点号“. ”分隔开的每一段独立的字符串称为一个单词),如“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”
        //binding key与routing key一样也是句点号“. ”分隔的字符串
        //binding key中可以存在两种特殊字符“*”与“#”,用于做模糊匹配,其中“*”用于匹配一个单词,“#”用于匹配多个单词(可以是零个)
        //   如果写成   "DIRECT_ROUTING_KEY_.*"  则为topic模式 即模糊匹配
        rabbitTemplate.convertAndSend("DIRECT_EXCHANGE", "DIRECT_ROUTING_KEY_A", p, correlationData);
        return ResponseEntity.ok();
    }

7.4.3 receiver端接收消息

  /**
     * DIRECT模式.
     *
     * @param message the message
     * @param channel the channel
     * @throws IOException the io exception  这里异常需要处理
     */
    @RabbitListener(queues = {"DIRECT_QUEUE_A"})
    public void messageA(Message message, Channel channel) throws IOException {
        log.debug("DIRECTA "+new String (message.getBody()));
    }
    /**
     * DIRECT模式.
     *
     * @param message the message
     * @param channel the channel
     * @throws IOException the io exception  这里异常需要处理
     */
    @RabbitListener(queues = {"DIRECT_QUEUE_B"})
    public void messageB(Message message, Channel channel) throws IOException {
        log.debug("DIRECTB "+new String (message.getBody()));
    }

只有队列A能够存储消息、消费者A能够收到消息

 

7.5 fanout类型 

广播模式 发送到exchange下所有的queue

7.5.1定义fanout类型队列、交换机并绑定:

 /* ----------------------------------------------------------------------------Fanout exchange test--------------------------------------------------------------------------- */

    /**
     * 声明 fanout 交换机.
     *
     * @return the exchange
     */
    @Bean("fanoutExchange")
    public FanoutExchange fanoutExchange() {
        return (FanoutExchange) ExchangeBuilder.fanoutExchange("FANOUT_EXCHANGE").durable(true).build();
    }

    /**
     * Fanout queue A.
     *
     * @return the queue
     */
    @Bean("fanoutQueueA")
    public Queue fanoutQueueA() {
        return QueueBuilder.durable("FANOUT_QUEUE_A").build();
    }

    /**
     * Fanout queue B .
     *
     * @return the queue
     */
    @Bean("fanoutQueueB")
    public Queue fanoutQueueB() {
        return QueueBuilder.durable("FANOUT_QUEUE_B").build();
    }

    /**
     * 绑定队列A 到Fanout 交换机.
     *
     * @param queue          the queue
     * @param fanoutExchange the fanout exchange
     * @return the binding
     */
    @Bean
    public Binding bindingA(@Qualifier("fanoutQueueA") Queue queue, @Qualifier("fanoutExchange") FanoutExchange fanoutExchange) {
        return BindingBuilder.bind(queue).to(fanoutExchange);
    }

    /**
     * 绑定队列B 到Fanout 交换机.
     *
     * @param queue          the queue
     * @param fanoutExchange the fanout exchange
     * @return the binding
     */
    @Bean
    public Binding bindingB(@Qualifier("fanoutQueueB") Queue queue, @Qualifier("fanoutExchange") FanoutExchange fanoutExchange) {
        return BindingBuilder.bind(queue).to(fanoutExchange);
    }

7.5.2 controller中发送消息

   /**
     * 测试广播模式.
     *  fanout类型的Exchange路由规则非常简单,它会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中。
     * @param p the p
     * @return the response entity
     */
    @RequestMapping("/fanout")
    public ResponseEntity send(String p) {
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());

        rabbitTemplate.convertAndSend("FANOUT_EXCHANGE", "", p, correlationData);
        return ResponseEntity.ok();
    }

7.5.3 receiver端接收消息

    /**
     * FANOUT广播队列监听一.
     *
     * @param message the message
     * @param channel the channel
     * @throws IOException the io exception  这里异常需要处理
     */
    @RabbitListener(queues = {"FANOUT_QUEUE_A"})
    public void on(Message message, Channel channel) throws IOException {
        log.debug("FANOUT_QUEUE_A "+new String(message.getBody()));
    }

    /**
     * FANOUT广播队列监听二.
     *
     * @param message the message
     * @param channel the channel
     * @throws IOException the io exception   这里异常需要处理
     */
    @RabbitListener(queues = {"FANOUT_QUEUE_B"})
    public void t(Message message, Channel channel) throws IOException {
        log.debug("FANOUT_QUEUE_B "+new String(message.getBody()));
    }

AB 都能接收到消息

 

7.6 diedletter类型(延迟消费类型)

A队列接收 过期后转发至B队列   B队列被消费 实现消息的延迟消费

原理图:

7.6.1定义diedletter类型队列、交换机并绑定:

  /*----------------------------------------------------------------------------deadletter queue------------------------------------------------------------------------------*/

    /**
     * 死信队列跟交换机类型没有关系 不一定为directExchange  不影响该类型交换机的特性.
     *
     * @return the exchange
     */
    @Bean("deadLetterExchange")
    public Exchange deadLetterExchange() {
        return ExchangeBuilder.directExchange("DL_EXCHANGE").durable(true).build();
    }

    /**
     * 声明一个死信队列.
     * x-dead-letter-exchange   对应  死信交换机
     * x-dead-letter-routing-key  对应 死信队列
     *
     * @return the queue
     */
    @Bean("deadLetterQueue")
    public Queue deadLetterQueue() {
        Map<String, Object> args = new HashMap<>(2);
//       x-dead-letter-exchange    声明  死信交换机
        args.put(DEAD_LETTER_QUEUE_KEY, "DL_EXCHANGE");
//       x-dead-letter-routing-key    声明 死信路由键
        args.put(DEAD_LETTER_ROUTING_KEY, "KEY_R");
        return QueueBuilder.durable("DL_QUEUE").withArguments(args).build();
    }

    /**
     * 定义死信队列转发队列.
     *
     * @return the queue
     */
    @Bean("redirectQueue")
    public Queue redirectQueue() {
        return QueueBuilder.durable("REDIRECT_QUEUE").build();
    }

    /**
     * 死信路由通过 DL_KEY 绑定键绑定到死信队列上.
     *
     * @return the binding
     */
    @Bean
    public Binding deadLetterBinding() {
        return new Binding("DL_QUEUE", Binding.DestinationType.QUEUE, "DL_EXCHANGE", "DL_KEY", null);

    }

    /**
     * 死信路由通过 KEY_R 绑定键绑定到死信队列上.
     *
     * @return the binding
     */
    @Bean
    public Binding redirectBinding() {
        return new Binding("REDIRECT_QUEUE", Binding.DestinationType.QUEUE, "DL_EXCHANGE", "KEY_R", null);
    }

7.6.2 controller中发送消息

    /**
     * 测试死信队列.
     *
     * @param p the p
     * @return the response entity
     */
    @RequestMapping("/dead")
    public ResponseEntity deadLetter(String p) {
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
//        声明消息处理器  这个对消息进行处理  可以设置一些参数   对消息进行一些定制化处理   我们这里  来设置消息的编码  以及消息的过期时间  因为在.net 以及其他版本过期时间不一致   这里的时间毫秒值 为字符串
        MessagePostProcessor messagePostProcessor = message -> {
            MessageProperties messageProperties = message.getMessageProperties();
//            设置编码
            messageProperties.setContentEncoding("utf-8");
//            设置过期时间10*1000毫秒
            messageProperties.setExpiration("2000");
            return message;
        };
//         向DL_QUEUE 发送消息  10*1000毫秒后过期 形成死信
        rabbitTemplate.convertAndSend("DL_EXCHANGE", "DL_KEY", p, messagePostProcessor, correlationData);
        return ResponseEntity.ok();
    }

7.6.3 receiver端接收消息

   /**
     * 监听替补队列 来验证死信.
     *
     * @param message the message
     * @param channel the channel
     * @throws IOException the io exception  这里异常需要处理
     */
    @RabbitListener(queues = {"REDIRECT_QUEUE"})
    public void redirect(Message message, Channel channel) throws IOException {
        log.debug("dead message  10s 后 消费消息 {}",new String (message.getBody()));
    }

过一会替补队列接收到了消息

 

7.7 topic类型

模糊匹配模式  这个routingkey与bindingkey采用正则通配符形式模糊匹配

7.7.1定义topic类型队列、交换机并绑定:

同7.4.1

7.7.2 controller中发送消息

    /**
     * 测试Direct模式.
     *direct类型的Exchange路由规则也很简单,它会把消息路由到那些binding key与routing key完全匹配的Queue中
     * @param p the p
     * @return the response entity
     */
    @RequestMapping("/direct")
    public ResponseEntity direct(String p) {
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        //routing key为一个句点号“. ”分隔的字符串(我们将被句点号“. ”分隔开的每一段独立的字符串称为一个单词),如“stock.usd.nyse”、“nyse.vmw”、“quick.orange.rabbit”
        //binding key与routing key一样也是句点号“. ”分隔的字符串
        //binding key中可以存在两种特殊字符“*”与“#”,用于做模糊匹配,其中“*”用于匹配一个单词,“#”用于匹配多个单词(可以是零个)
        //   如果写成   "DIRECT_ROUTING_KEY_.*"  则为topic模式 即模糊匹配
        rabbitTemplate.convertAndSend("DIRECT_EXCHANGE", "DIRECT_ROUTING_KEY_.*", p, correlationData);
        return ResponseEntity.ok();
    }

7.7.3 receiver端接收消息

同7.4.3

这个时候AB队列都能够收到消息,且他们的监听这也能监听到同样的消息

8.上代码

 

这个源码亲测可用的哈,下载后直接浏览器调用controller对应的demo就能看验证效果了

下载地址:https://pan.baidu.com/s/1J3JQoyNv0_gfiy_p3hrZZg

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章