RabbitMQ 研究和SpringBoot 整合

1 介紹

     MQ全稱爲Message Queue,即消息隊列, RabbitMQ是由erlang語言開發,基於AMQP(Advanced Message
Queue 高級消息隊列協議)協議實現的消息隊列,它是一種應用程序之間的通信方法,消息隊列在分佈式系統開
發中應用非常廣泛。

 開發中消息隊列通常有如下應用場景:
1、任務異步處理。
將不需要同步處理的並且耗時長的操作由消息隊列通知消息接收方進行異步處理。提高了應用程序的響應時間。
2、應用程序解耦合
MQ相當於一箇中介,生產方通過MQ與消費方交互,它將應用程序進行解耦合。

2.jms和AMQP

    AMQP是一套公開的消息隊列協議,最早在2003年被提出,它旨在從協議層定義消息通信數據的標準格式,
爲的就是解決MQ市場上協議不統一的問題。RabbitMQ就是遵循AMQP標準協議開發的MQ服務。

    JMS是java提供的一套消息服務API標準,其目的是爲所有的java應用程序提供統一的消息通信的標準,類似java的
jdbc,只要遵循jms標準的應用程序之間都可以進行消息通信。

jms是java語言專屬的消息服務標準,它是在api層定義標準,並且只能用於java應用;而AMQP是在協議層定義的標準,是跨語言的 。

案例:

/**
 * 作者: lin
 * 描述: 生產者
 * 日期: 2018/12/13 11:24
 */
public class test01 {

    //隊列
    private static final String QUEUE = "helloworldduilie";

    public static void main(String[] args) {
        // 創建連接工廠創建新的連接和mq連接
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        //設置虛擬機,一個mq服務可以設置多個虛擬機,每個虛擬機就相當於一個獨立的mq
        connectionFactory.setVirtualHost("/");
        Connection connection = null;
        Channel channel = null;
        try {
            // 建立連接
            connection = connectionFactory.newConnection();
            // 創建會話通道,生產者所有mq都在通道里
            channel = connection.createChannel();
            // 聲明隊列
            /**
             * 參數明細
             * 1、queue 隊列名稱
             * 2、durable 是否持久化,如果持久化,mq重啓後隊列還在
             * 3、exclusive 是否獨佔連接,隊列只允許在該連接中訪問,如果connection連接關閉隊列則自動刪除,如果將此參數設置true可用於臨時隊列的創建
             * 4、autoDelete 自動刪除,隊列不再使用時是否自動刪除此隊列,如果將此參數和exclusive參數設置爲true就可以實現臨時隊列(隊列不用了就自動刪除)
             * 5、arguments 參數,可以設置一個隊列的擴展參數,比如:可設置存活時間
             */
            channel.queueDeclare(QUEUE, true, false, false, null);
            /**
             * 參數明細:
             * 1、exchange,交換機,如果不指定將使用mq的默認交換機(設置爲"")
             * 2、routingKey,路由key,交換機根據路由key來將消息轉發到指定的隊列,如果使用默認交換機,routingKey設置爲隊列的名稱
             * 3、props,消息的屬性
             * 4、body,消息內容
             */
            String message = "hello rabbitMq44";
            channel.basicPublish("",QUEUE,null,message.getBytes());
            System.out.println("send to mq "+message);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 先關連接,連接在通道里面
            try {
                channel.close();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (TimeoutException e) {
                e.printStackTrace();
            }
            try {
                connection.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

消費者

/**
 * 作者: lin
 * 描述: 消費者
 * 日期: 2018/12/13 14:54
 */
public class test01consumer {

    //隊列
    private static final String QUEUE = "helloworldduilie";

    public static void main(String[] args) throws IOException, TimeoutException {
        // 創建連接工廠創建新的連接和mq連接
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        //設置虛擬機,一個mq服務可以設置多個虛擬機,每個虛擬機就相當於一個獨立的mq
        connectionFactory.setVirtualHost("/");
        Connection connection = null;
        Channel channel = null;
        // 建立連接
        connection = connectionFactory.newConnection();
        // 創建會話通道,生產者所有mq都在通道里
        channel = connection.createChannel();
        // 聲明隊列
        /**
         * 參數明細
         * 1、queue 隊列名稱
         * 2、durable 是否持久化,如果持久化,mq重啓後隊列還在
         * 3、exclusive 是否獨佔連接,隊列只允許在該連接中訪問,如果connection連接關閉隊列則自動刪除,如果將此參數設置true可用於臨時隊列的創建
         * 4、autoDelete 自動刪除,隊列不再使用時是否自動刪除此隊列,如果將此參數和exclusive參數設置爲true就可以實現臨時隊列(隊列不用了就自動刪除)
         * 5、arguments 參數,可以設置一個隊列的擴展參數,比如:可設置存活時間
         */
        channel.queueDeclare(QUEUE, true, false, false, null);

        // 消費方法 ctrl + o
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel){

        /**
         * 當接收到消息後此方法將被調用
         * @param consumerTag  消費者標籤,用來標識消費者的,在監聽隊列時設置channel.basicConsume
         * @param envelope 信封,通過envelope
         * @param properties 消息屬性
         * @param body 消息內容
         * @throws IOException
         */
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {

            // 獲取交換機
            String exchange = envelope.getExchange();
            //消息id,mq在channel中用來標識消息的id,可用於確認消息已接收
            long deliveryTag = envelope.getDeliveryTag();
            //消息內容
            String message = new String(body,"utf-8");
            System.out.println("交換機爲"+exchange+"消息id"+deliveryTag+"消息內容"+message);
        }
        };
        /**
         * 監聽隊列
         * 參數明細:
         * 1、queue 隊列名稱
         * 2、autoAck 自動回覆,當消費者接收到消息後要告訴mq消息已接收,如果將此參數設置爲tru表示會自動回覆mq,如果設置爲false要通過編程實現回覆
         * 3、callback,消費方法,當消費者接收到消息要執行的方法
         */
        channel.basicConsume(QUEUE,true,defaultConsumer);

    }

這裏只關閉了生產者,消費者必須一直監聽所以不做關閉,還是有點意思的...

3.總結

1、發送端操作流程
1)創建連接            2)創建通道             3)聲明隊列            4)發送消息


2、接收端

1)創建連接           2)創建通道                3)聲明隊列            4)監聽隊列             5)接收消息             6)ack回覆

4.工作模式

   1.Work queues

應用場景:對於 任務過重或任務較多情況使用工作隊列可以提高任務處理的速度。個人感覺沒啥用看看就行

2.發佈訂閱  比較常用

發佈訂閱模式:
1、每個消費者監聽自己的隊列。
2、生產者將消息發給broker,由交換機將消息轉發到綁定此交換機的每個隊列,每個綁定交換機的隊列都將接收
到消息

代碼案例:當用戶充值成功或轉賬完成系統通知用戶,通知方式有短信、郵件多種方法 。

生產者

public class Producer02_publish {
    //隊列名稱
    private static final String QUEUE_INFORM_EMAIL = "queue_inform_email";
    private static final String QUEUE_INFORM_SMS = "queue_inform_sms";
    private static final String EXCHANGE_FANOUT_INFORM="exchange_fanout_inform";

    public static void main(String[] args) {
        //通過連接工廠創建新的連接和mq建立連接
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);//端口
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        //設置虛擬機,一個mq服務可以設置多個虛擬機,每個虛擬機就相當於一個獨立的mq
        connectionFactory.setVirtualHost("/");

        Connection connection = null;
        Channel channel = null;
        try {
            //建立新連接
            connection = connectionFactory.newConnection();
            //創建會話通道,生產者和mq服務所有通信都在channel通道中完成
            channel = connection.createChannel();
            //聲明隊列,如果隊列在mq 中沒有則要創建
            //參數:String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
            /**
             * 參數明細
             * 1、queue 隊列名稱
             * 2、durable 是否持久化,如果持久化,mq重啓後隊列還在
             * 3、exclusive 是否獨佔連接,隊列只允許在該連接中訪問,如果connection連接關閉隊列則自動刪除,如果將此參數設置true可用於臨時隊列的創建
             * 4、autoDelete 自動刪除,隊列不再使用時是否自動刪除此隊列,如果將此參數和exclusive參數設置爲true就可以實現臨時隊列(隊列不用了就自動刪除)
             * 5、arguments 參數,可以設置一個隊列的擴展參數,比如:可設置存活時間
             */
            channel.queueDeclare(QUEUE_INFORM_EMAIL,true,false,false,null);
            channel.queueDeclare(QUEUE_INFORM_SMS,true,false,false,null);
            //聲明一個交換機
            //參數:String exchange, String type
            /**
             * 參數明細:
             * 1、交換機的名稱
             * 2、交換機的類型
             * fanout:對應的rabbitmq的工作模式是 publish/subscribe
             * direct:對應的Routing	工作模式
             * topic:對應的Topics工作模式
             * headers: 對應的headers工作模式
             */
            channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM, BuiltinExchangeType.FANOUT);
            //進行交換機和隊列綁定
            //參數:String queue, String exchange, String routingKey
            /**
             * 參數明細:
             * 1、queue 隊列名稱
             * 2、exchange 交換機名稱
             * 3、routingKey 路由key,作用是交換機根據路由key的值將消息轉發到指定的隊列中,在發佈訂閱模式中調協爲空字符串
             */
            channel.queueBind(QUEUE_INFORM_EMAIL,EXCHANGE_FANOUT_INFORM,"");
            channel.queueBind(QUEUE_INFORM_SMS,EXCHANGE_FANOUT_INFORM,"");
            //發送消息
            //參數:String exchange, String routingKey, BasicProperties props, byte[] body
            /**
             * 參數明細:
             * 1、exchange,交換機,如果不指定將使用mq的默認交換機(設置爲"")
             * 2、routingKey,路由key,交換機根據路由key來將消息轉發到指定的隊列,如果使用默認交換機,routingKey設置爲隊列的名稱
             * 3、props,消息的屬性
             * 4、body,消息內容
             */
            for(int i=0;i<5;i++){
                //消息內容
                String message = "send inform message to user";
                channel.basicPublish(EXCHANGE_FANOUT_INFORM,"",null,message.getBytes());
                System.out.println("send to mq "+message);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //關閉連接
            //先關閉通道
            try {
                channel.close();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (TimeoutException e) {
                e.printStackTrace();
            }
            try {
                connection.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }
}

消費者:

public class test02Consumer {

    //隊列名稱
    private static final String QUEUE_INFORM_EMAIL = "queue_inform_email";
    private static final String EXCHANGE_FANOUT_INFORM="exchange_fanout_inform";


    public static void main(String[] args) throws IOException, TimeoutException {
        //通過連接工廠創建新的連接和mq建立連接
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("127.0.0.1");
        connectionFactory.setPort(5672);//端口
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        //設置虛擬機,一個mq服務可以設置多個虛擬機,每個虛擬機就相當於一個獨立的mq
        connectionFactory.setVirtualHost("/");

        //建立新連接
        Connection connection = connectionFactory.newConnection();
        //創建會話通道,生產者和mq服務所有通信都在channel通道中完成
        Channel channel = connection.createChannel();

        /**
         * 參數明細
         * 1、queue 隊列名稱
         * 2、durable 是否持久化,如果持久化,mq重啓後隊列還在
         * 3、exclusive 是否獨佔連接,隊列只允許在該連接中訪問,如果connection連接關閉隊列則自動刪除,如果將此參數設置true可用於臨時隊列的創建
         * 4、autoDelete 自動刪除,隊列不再使用時是否自動刪除此隊列,如果將此參數和exclusive參數設置爲true就可以實現臨時隊列(隊列不用了就自動刪除)
         * 5、arguments 參數,可以設置一個隊列的擴展參數,比如:可設置存活時間
         */
        channel.queueDeclare(QUEUE_INFORM_EMAIL,true,false,false,null);
        //聲明一個交換機
        //參數:String exchange, String type
        /**
         * 參數明細:
         * 1、交換機的名稱
         * 2、交換機的類型
         * fanout:對應的rabbitmq的工作模式是 publish/subscribe
         * direct:對應的Routing	工作模式
         * topic:對應的Topics工作模式
         * headers: 對應的headers工作模式
         */
        channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM, BuiltinExchangeType.FANOUT);
        //進行交換機和隊列綁定
        //參數:String queue, String exchange, String routingKey
        /**
         * 參數明細:
         * 1、queue 隊列名稱
         * 2、exchange 交換機名稱
         * 3、routingKey 路由key,作用是交換機根據路由key的值將消息轉發到指定的隊列中,在發佈訂閱模式中調協爲空字符串
         */
        channel.queueBind(QUEUE_INFORM_EMAIL, EXCHANGE_FANOUT_INFORM, "");

        //實現消費方法
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel){

            /**
             * 當接收到消息後此方法將被調用
             * @param consumerTag  消費者標籤,用來標識消費者的,在監聽隊列時設置channel.basicConsume
             * @param envelope 信封,通過envelope
             * @param properties 消息屬性
             * @param body 消息內容
             * @throws IOException
             */
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                //交換機
                String exchange = envelope.getExchange();
                //消息id,mq在channel中用來標識消息的id,可用於確認消息已接收
                long deliveryTag = envelope.getDeliveryTag();
                //消息內容
                String message= new String(body,"utf-8");
                System.out.println("receive message:"+message);
            }
        };

        //監聽隊列
        //參數:String queue, boolean autoAck, Consumer callback
        /**
         * 參數明細:
         * 1、queue 隊列名稱
         * 2、autoAck 自動回覆,當消費者接收到消息後要告訴mq消息已接收,如果將此參數設置爲tru表示會自動回覆mq,如果設置爲false要通過編程實現回覆
         * 3、callback,消費方法,當消費者接收到消息要執行的方法
         */
        channel.basicConsume(QUEUE_INFORM_EMAIL,true,defaultConsumer);

    }
}

其他雷同。這是強化版的Work queues,一個消費者綁定一個交換機,通道中設置自己監聽的隊列。

3. Routing

加強版的發佈訂閱,使用路由可以指定通道,可以使用雙通道也可以使用單通道,比較強大。

路由模式:

   1、每個消費者監聽自己的隊列,並且設置routingkey。
   2、生產者將消息發給交換機,由交換機根據routingkey來轉發消息到指定的隊列。

1、生產者
      聲明exchange_routing_inform交換機。
      聲明兩個隊列並且綁定到此交換機,綁定時需要指定routingkey
      發送消息時需要指定routingkey

package com.xuecheng.test.rabbitmq;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Producer03_routing {
//隊列名稱
private static final String QUEUE_INFORM_EMAIL = "queue_inform_email";
private static final String QUEUE_INFORM_SMS = "queue_inform_sms";
private static final String EXCHANGE_ROUTING_INFORM="exchange_routing_inform";
public static void main(String[] args) {
Connection connection = null;
Channel channel = null;
try {
//創建一個與MQ的連接
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
factory.setVirtualHost("/");//rabbitmq默認虛擬機名稱爲“/”,虛擬機相當於一個獨立的mq服務
器
//創建一個連接
connection = factory.newConnection();
//創建與交換機的通道,每個通道代表一個會話
channel = connection.createChannel();
//聲明交換機 String exchange, BuiltinExchangeType type
/**
* 參數明細
* 1、交換機名稱
* 2、交換機類型,fanout、topic、direct、headers
*/
channel.exchangeDeclare(EXCHANGE_ROUTING_INFORM, BuiltinExchangeType.DIRECT);
//聲明隊列
// channel.queueDeclare(String queue, boolean durable, boolean exclusive, boolean
autoDelete, Map<String, Object> arguments)
/**
* 參數明細:
* 1、隊列名稱
* 2、是否持久化
* 3、是否獨佔此隊列
* 4、隊列不用是否自動刪除
* 5、參數
*/
channel.queueDeclare(QUEUE_INFORM_EMAIL, true, false, false, null);
channel.queueDeclare(QUEUE_INFORM_SMS, true, false, false, null);
//交換機和隊列綁定String queue, String exchange, String routingKey
/**
* 參數明細
* 1、隊列名稱
* 2、交換機名稱
* 3、路由key
*/
channel.queueBind(QUEUE_INFORM_EMAIL,EXCHANGE_ROUTING_INFORM,QUEUE_INFORM_EMAIL);
channel.queueBind(QUEUE_INFORM_SMS,EXCHANGE_ROUTING_INFORM,QUEUE_INFORM_SMS);
//發送郵件消息
for (int i=0;i<10;i++){
String message = "email inform to user"+i;
//向交換機發送消息 String exchange, String routingKey, BasicProperties props,
byte[] body
/**
* 參數明細
* 1、交換機名稱,不指令使用默認交換機名稱 Default Exchange
* 2、routingKey(路由key),根據key名稱將消息轉發到具體的隊列,這裏填寫隊列名稱表示消
息將發到此隊列
* 3、消息屬性
* 4、消息內容
*/
channel.basicPublish(EXCHANGE_ROUTING_INFORM, QUEUE_INFORM_EMAIL, null,
message.getBytes());
System.out.println("Send Message is:'" + message + "'");
}
//發送短信消息
for (int i=0;i<10;i++){
String message = "sms inform to user"+i;
//向交換機發送消息 String exchange, String routingKey, BasicProperties props,
byte[] body
channel.basicPublish(EXCHANGE_ROUTING_INFORM, QUEUE_INFORM_SMS, null,
message.getBytes());
System.out.println("Send Message is:'" + message + "'");
}
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}finally{
if(channel!=null){
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
if(connection!=null){
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

2、郵件發送消費者

package com.xuecheng.test.rabbitmq;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer03_routing_email {
//隊列名稱
private static final String QUEUE_INFORM_EMAIL = "inform_queue_email";
private static final String EXCHANGE_ROUTING_INFORM="inform_exchange_routing";
public static void main(String[] args) throws IOException, TimeoutException {
//創建一個與MQ的連接
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
factory.setVirtualHost("/");//rabbitmq默認虛擬機名稱爲“/”,虛擬機相當於一個獨立的mq服務器
//創建一個連接
Connection connection = factory.newConnection();
//創建與交換機的通道,每個通道代表一個會話
Channel channel = connection.createChannel();
//聲明交換機 String exchange, BuiltinExchangeType type
/**
* 參數明細
* 1、交換機名稱
* 2、交換機類型,fanout、topic、direct、headers
*/
channel.exchangeDeclare(EXCHANGE_ROUTING_INFORM, BuiltinExchangeType.DIRECT);
//聲明隊列
// channel.queueDeclare(String queue, boolean durable, boolean exclusive, boolean
autoDelete, Map<String, Object> arguments)
/**
* 參數明細:
* 1、隊列名稱
* 2、是否持久化
* 3、是否獨佔此隊列
* 4、隊列不用是否自動刪除
* 5、參數
*/
channel.queueDeclare(QUEUE_INFORM_EMAIL, true, false, false, null);
//交換機和隊列綁定String queue, String exchange, String routingKey
/**
* 參數明細
* 1、隊列名稱
* 2、交換機名稱
* 3、路由key
*/
channel.queueBind(QUEUE_INFORM_EMAIL,EXCHANGE_ROUTING_INFORM,QUEUE_INFORM_EMAIL);
//定義消費方法
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
AMQP.BasicProperties properties, byte[] body) throws IOException {
long deliveryTag = envelope.getDeliveryTag();
String exchange = envelope.getExchange();
//消息內容
String message = new String(body, "utf‐8");
System.out.println(message);
}
};
/**
* 監聽隊列String queue, boolean autoAck,Consumer callback
* 參數明細
* 1、隊列名稱
* 2、是否自動回覆,設置爲true爲表示消息接收到自動向mq回覆接收到了,mq接收到回覆會刪除消息,設置
爲false則需要手動回覆
* 3、消費消息的方法,消費者接收到消息後調用此方法
*/
channel.basicConsume(QUEUE_INFORM_EMAIL, true, defaultConsumer);
}
}


使用Routing模式也可以實現本案例,共設置三個 routingkey,分別是email、sms、all,email隊列綁定email和
all,sms隊列綁定sms和all,這樣就可以實現上邊案例的功能,實現過程比topics複雜。
Topic模式更多加強大,它可以實現Routing、publish/subscirbe模式的功能。

RPC

RPC即客戶端遠程調用服務端的方法 ,使用MQ可以實現RPC的異步調用,基於Direct交換機實現,流程如下:
1、客戶端即是生產者就是消費者,向RPC請求隊列發送RPC調用消息,同時監聽RPC響應隊列。
2、服務端監聽RPC請求隊列的消息,收到消息後執行服務端的方法,得到方法返回的結果
3、服務端將RPC方法 的結果發送到RPC響應隊列
4、客戶端(RPC調用方)監聽RPC響應隊列,接收到RPC調用結果。

Spring整合RibbitMQ

1.添加依賴

<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐logging</artifactId>
</dependency>

2.設置配置

1、配置application.yml,配置連接rabbitmq的參數

server:
port: 44000
spring:
application:
name: test‐rabbitmq‐producer
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtualHost: /

3.定義RabbitConfig類,配置Exchange、Queue、及綁定交換機

package com.xuecheng.test.rabbitmq.config;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitmqConfig {
public static final String QUEUE_INFORM_EMAIL = "queue_inform_email";
public static final String QUEUE_INFORM_SMS = "queue_inform_sms";
public static final String EXCHANGE_TOPICS_INFORM="exchange_topics_inform";
/**
* 交換機配置
* ExchangeBuilder提供了fanout、direct、topic、header交換機類型的配置
* @return the exchange
*/
@Bean(EXCHANGE_TOPICS_INFORM)
public Exchange EXCHANGE_TOPICS_INFORM() {
//durable(true)持久化,消息隊列重啓後交換機仍然存在
return ExchangeBuilder.topicExchange(EXCHANGE_TOPICS_INFORM).durable(true).build();
}
//聲明隊列
@Bean(QUEUE_INFORM_SMS)
public Queue QUEUE_INFORM_SMS() {
Queue queue = new Queue(QUEUE_INFORM_SMS);
return queue;
}
//聲明隊列
@Bean(QUEUE_INFORM_EMAIL)
public Queue QUEUE_INFORM_EMAIL() {
Queue queue = new Queue(QUEUE_INFORM_EMAIL);
return queue;
}
/** channel.queueBind(INFORM_QUEUE_SMS,"inform_exchange_topic","inform.#.sms.#");
* 綁定隊列到交換機 .
*
* @param queue the queue
* @param exchange the exchange
* @return the binding
*/
@Bean
public Binding BINDING_QUEUE_INFORM_SMS(@Qualifier(QUEUE_INFORM_SMS) Queue queue,
@Qualifier(EXCHANGE_TOPICS_INFORM) Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("inform.#.sms.#").noargs();
}
@Bean
public Binding BINDING_QUEUE_INFORM_EMAIL(@Qualifier(QUEUE_INFORM_EMAIL) Queue queue,
@Qualifier(EXCHANGE_TOPICS_INFORM) Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("inform.#.email.#").noargs();
}
}

4.生產端,使用用RarbbitTemplate發消息

package com.xuecheng.test.rabbitmq;
import com.xuecheng.test.rabbitmq.config.RabbitmqConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest
@RunWith(SpringRunner.class)
public class Producer05_topics_springboot {
@Autowired
RabbitTemplate rabbitTemplate;
@Test
public void testSendByTopics(){
for (int i=0;i<5;i++){
String message = "sms email inform to user"+i;
rabbitTemplate.convertAndSend(RabbitmqConfig.EXCHANGE_TOPICS_INFORM,"inform.sms.email",message);
System.out.println("Send Message is:'" + message + "'");
}
}
}

5.消費端,創建消費端工程,添加依賴

<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐logging</artifactId>
</dependency>

使用@RabbitListener註解監聽隊列。

package com.xuecheng.test.rabbitmq.mq;
import com.rabbitmq.client.Channel;
import com.xuecheng.test.rabbitmq.config.RabbitmqConfig;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class ReceiveHandler {
//監聽email隊列
@RabbitListener(queues = {RabbitmqConfig.QUEUE_INFORM_EMAIL})
public void receive_email(String msg,Message message,Channel channel){
System.out.println(msg);
}
//監聽sms隊列
@RabbitListener(queues = {RabbitmqConfig.QUEUE_INFORM_SMS})
public void receive_sms(String msg,Message message,Channel channel){
System.out.println(msg);
}
}

---------------編寫不易,轉載請寫出處--------------------------

 

 

 

 

 

 

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