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

 

 

 

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