訊息佇列之RabbitMQ

pluto_charon發表於2021-01-17

1.rabbitMQ介紹

rabbitMQ是由erlang語言開發的,基於AMQP協議實現的訊息佇列。他是一種應用程式之間的通訊方法,在分散式系統開發中應用非常廣泛。

rabbitMq的有點:

  1. 使用簡單,功能強大
  2. 基於AMQP協議
  3. 社群活躍,文件完善
  4. 高併發效能好,erlang語言是專門用於開發高併發程式的
  5. springBoot預設整合rabbitMq

AMQP(advanced Message Queuing Protocol),是一個提供統一訊息服務的應用標準高階訊息佇列協議,是應用層協議的一個開放標準,為面向訊息的中介軟體設計,基於此協議的客戶端與訊息中介軟體可傳遞訊息,並不受客戶端中介軟體的產品不同和開發語言不同的限制。JMS和AMQP的區別在於:JMS是java語言專屬的訊息服務標準,他是在api層定義標準,並且只能用於java應用,而AMQP是在協議層定義的標準,是可以跨語言的。

2.工作流程

傳送訊息:

  1. 生產者和broker建立TCP連線
  2. 生產者和broker建立通道
  3. 生產者通過通道訊息傳送給broker,由exchange將訊息轉發
  4. exchange將訊息轉發給指定的queue

接受訊息:

  1. 消費者和broker建立TCP連線
  2. 消費者和broker建立通道
  3. 消費者監聽指定的queue
  4. 當有訊息到達queue的時候broker預設將訊息推送給消費者
  5. 消費者接受到訊息並消費

3.安裝

如果不想自己下載,需要我這裡的軟體的,可以在下面評論郵箱,我私發給你。

1.安裝erlang的環境,雙擊otp的執行程式,然後一路點選下一步(next)。

配置環境變數

在path中新增erlang的路徑

2.安裝rabbitMq,雙擊rabbitmq的執行程式

安裝完成之後在選單頁面可以看到

安裝完RabbitMQ如果想要訪問管理頁面需要在rabbitmq的sbin目錄中使用cmd執行:rabbitmq-plugins.bat enable rabbitmq_management(管理員身份執行此命令)新增視覺化外掛。

點選上圖中的start/stop來開啟/停止服務。然後在瀏覽器上輸入地址檢視,rabbitMq的預設埠是15672。預設的使用者名稱和密碼都是guest

如果安裝失敗,需要解除安裝重灌的時候或者出現rabbitMq服務註冊失敗時,此時需要進入登錄檔清理erlang(搜尋rabbitMQ,erlsrv將對應的項刪除)

4.程式碼實現

1.新增依賴

<!--新增rabbitMq的依賴-->
<dependency>
	<groupId>com.rabbitmq</groupId>
	<artifactId>amqp-client</artifactId>
	<version>5.7.3</version>
</dependency>

2.生產者程式碼實現

package rabbitmq;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.net.ConnectException;
import java.util.concurrent.TimeoutException;

/**
 * @className: producer
 * @description: rabbitmq的生產者程式碼實現
 * @author: charon
 * @create: 2021-01-03 23:10
 */
public class Producer {
    /**
     * 宣告佇列名
     */
    private static final String QUEUE = "hello charon";

    public static void main(String[] args) {
        // 建立連線工廠
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 設定ip,埠,因為是本機,所以直接設定為127.0.0.1
        connectionFactory.setHost("127.0.0.1");
        // web埠預設為15672,通訊埠為5672
        connectionFactory.setPort(5672);
        // 設定使用者名稱和密碼
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        // 設定虛擬ip,預設為/,一個rabbitmq的服務可以設定多個虛擬機器,每個虛擬機器就相當於一個獨立的mq
        connectionFactory.setVirtualHost("/");
        Connection connection = null;
        Channel channel = null;
        try {
            connection = connectionFactory.newConnection();
            // 建立通道
            channel = connection.createChannel();
            // 宣告佇列(佇列名稱,是否持久化,是否排它,是否自動刪除,佇列的擴充套件引數比如設定存活時間等)
            channel.queueDeclare(QUEUE, true, false, false, null);
            String message = "hello charon good evening";
            // 釋出訊息(交換機,RoutingKey即佇列名,額外的訊息屬性,訊息內容)
            channel.basicPublish("", QUEUE, null, message.getBytes());
            System.out.println("傳送訊息給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();
            }
        }
    }
}

3.消費者程式碼實現

package rabbitmq;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @className: Consumer
 * @description: 消費者的程式碼實現
 * @author: charon
 * @create: 2021-01-05 08:28
 */
public class Consumer {
    /**
     * 宣告佇列名
     */
    private static final String QUEUE = "hello charon";

    public static void main(String[] args) throws IOException, TimeoutException {
        // 建立連線工廠
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 設定ip,埠,因為是本機,所以直接設定為127.0.0.1
        connectionFactory.setHost("127.0.0.1");
        // web埠預設為15672,通訊埠為5672
        connectionFactory.setPort(5672);
        // 設定使用者名稱和密碼
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        // 設定虛擬ip,預設為/,一個rabbitmq的服務可以設定多個虛擬機器,每個虛擬機器就相當於一個獨立的mq
        connectionFactory.setVirtualHost("/");
        Connection connection = connectionFactory.newConnection();
        // 建立通道
        Channel channel = connection.createChannel();
        // 宣告佇列(佇列名稱,是否持久化,是否排它,是否自動刪除,佇列的擴充套件引數比如設定存活時間等)
        channel.queueDeclare(QUEUE, true, false, false, null);
        // 實現消費方法
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
            /**
             *
             * @param consumerTag 消費者標籤
             * @param 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();
//                long deliveryTag = envelope.getDeliveryTag();
                String message = new String(body,"utf-8");
                System.out.println("收到的訊息是:"+message);
            }
        };
        // 消費訊息(佇列名,是否自動確認,消費方法)
        channel.basicConsume(QUEUE,true,defaultConsumer);
    }
}

5.rabbitMq的工作模式

  1. Work queues 工作佇列(資源競爭)

​ 生產者將訊息放入到佇列中,消費者可以有多個,同時監聽同一個佇列。如上圖,消費者c1,c2共同爭搶當前訊息佇列的內容,誰先拿到誰負責消費訊息,缺點是在高併發的情況下,預設會產品一個訊息被多個消費者共同使用,可以設定一個鎖開關,保證一條訊息只能被一個消費者使用。

上面的程式碼,可以再新增一個消費者,這樣就可以實現工作佇列的工作模式。

2.Publish/Subscribe 釋出訂閱(共享資源)

X代表rabbitMq內部元件交換機,生產者將訊息放入交換機,交換機發布訂閱把訊息傳送到所有訊息佇列中,對應的消費者拿到訊息進行消費,對比工作佇列而言,釋出訂閱可以實現工作佇列的功能,但是比工作佇列更強大。

特點:
1.每個消費者監聽自己的佇列
2.生產者將訊息傳送給Broker,由交換機將訊息轉發到繫結的此交換機的每個佇列,每個繫結交換機的佇列都將接收到訊息;

生產者:

package rabbitmq.publish;

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;

/**
 * @className: Producer
 * @description: 釋出訂閱的生產者
 * @author: charon
 * @create: 2021-01-07 22:02
 */
public class Producer {

    /**郵件的佇列*/
    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_FANOUT_INFORM = "exchange_fanout_inform";

    public static void main(String[] args) {
        // 建立連線工廠
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 設定ip,埠,因為是本機,所以直接設定為127.0.0.1
        connectionFactory.setHost("127.0.0.1");
        // web埠預設為15672,通訊埠為5672
        connectionFactory.setPort(5672);
        // 設定使用者名稱和密碼
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        // 設定虛擬ip,預設為/,一個rabbitmq的服務可以設定多個虛擬機器,每個虛擬機器就相當於一個獨立的mq
        connectionFactory.setVirtualHost("/");
        Connection connection = null;
        Channel channel = null;
        try {
            connection = connectionFactory.newConnection();
            // 建立通道
            channel = connection.createChannel();
            // 宣告佇列(佇列名稱,是否持久化,是否排它,是否自動刪除,佇列的擴充套件引數比如設定存活時間等)
            channel.queueDeclare(QUEUE_INFORM_EMAIL, true, false, false, null);
            channel.queueDeclare(QUEUE_INFORM_SMS, true, false, false, null);
            // 交換機(交換機名稱,交換機型別(fanout:釋出訂閱,direct:routing,topic:主題,headers:header模式))
            channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM, BuiltinExchangeType.FANOUT);
            // 繫結交換機(佇列名稱,交換機名稱,routingKey(釋出訂閱設定為空))
            channel.queueBind(QUEUE_INFORM_EMAIL,EXCHANGE_FANOUT_INFORM,"");
            channel.queueBind(QUEUE_INFORM_SMS,EXCHANGE_FANOUT_INFORM,"");
            // 傳送多條訊息
            for (int i = 0; i < 5; i++) {
                String message = "hello charon good evening by publish";
                // 指定交換機(交換機,RoutingKey即佇列名,額外的訊息屬性,訊息內容)
                channel.basicPublish(EXCHANGE_FANOUT_INFORM, "", null, message.getBytes());
                System.out.println("傳送訊息給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();
            }
        }
    }
}

消費email的消費者:

package rabbitmq.publish;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @className: EmailConsumer
 * @description: 郵件的訊息消費者
 * @author: charon
 * @create: 2021-01-07 22:14
 */
public class EmailConsumer {

    /**郵件的佇列*/
    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_FANOUT_INFORM = "exchange_fanout_inform";

    public static void main(String[] args) throws IOException, TimeoutException {
        // 建立連線工廠
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 設定ip,埠,因為是本機,所以直接設定為127.0.0.1
        connectionFactory.setHost("127.0.0.1");
        // web埠預設為15672,通訊埠為5672
        connectionFactory.setPort(5672);
        // 設定使用者名稱和密碼
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        // 設定虛擬ip,預設為/,一個rabbitmq的服務可以設定多個虛擬機器,每個虛擬機器就相當於一個獨立的mq
        connectionFactory.setVirtualHost("/");
        Connection connection = connectionFactory.newConnection();
        // 建立通道
        Channel channel = connection.createChannel();
        // 宣告佇列(佇列名稱,是否持久化,是否排它,是否自動刪除,佇列的擴充套件引數比如設定存活時間等)
        channel.queueDeclare(QUEUE_INFORM_EMAIL, true, false, false, null);
        channel.queueDeclare(QUEUE_INFORM_SMS, true, false, false, null);
        channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM, BuiltinExchangeType.FANOUT);
        // 實現消費方法
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
            /**
             *
             * @param consumerTag 消費者標籤
             * @param 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();
//                long deliveryTag = envelope.getDeliveryTag();
                String message = new String(body,"utf-8");
                System.out.println("收到的email訊息是:"+message);
            }
        };
        // 消費訊息(佇列名,是否自動確認,消費方法)
        channel.basicConsume(QUEUE_INFORM_EMAIL,true,defaultConsumer);
    }
}

消費簡訊的消費者:

package rabbitmq.publish;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @className: SmsConsumer
 * @description:
 * @author: charon
 * @create: 2021-01-07 22:17
 */
public class SmsConsumer {


    /**郵件的佇列*/
    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_FANOUT_INFORM = "exchange_fanout_inform";

    public static void main(String[] args) throws IOException, TimeoutException {
        // 建立連線工廠
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 設定ip,埠,因為是本機,所以直接設定為127.0.0.1
        connectionFactory.setHost("127.0.0.1");
        // web埠預設為15672,通訊埠為5672
        connectionFactory.setPort(5672);
        // 設定使用者名稱和密碼
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        // 設定虛擬ip,預設為/,一個rabbitmq的服務可以設定多個虛擬機器,每個虛擬機器就相當於一個獨立的mq
        connectionFactory.setVirtualHost("/");
        Connection connection = connectionFactory.newConnection();
        // 建立通道
        Channel channel = connection.createChannel();
        // 宣告佇列(佇列名稱,是否持久化,是否排它,是否自動刪除,佇列的擴充套件引數比如設定存活時間等)
        channel.queueDeclare(QUEUE_INFORM_EMAIL, true, false, false, null);
        channel.queueDeclare(QUEUE_INFORM_SMS, true, false, false, null);
        channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM, BuiltinExchangeType.FANOUT);
        // 實現消費方法
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
            /**
             *
             * @param consumerTag 消費者標籤
             * @param envelope 信封,可以獲取交換機等資訊
             * @param properties 訊息屬性
             * @param body 消費內容,位元組陣列,可以轉成字串
             * @throws IOException
             */
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message = new String(body,"utf-8");
                System.out.println("收到的簡訊訊息是:"+message);
            }
        };
        // 消費訊息(佇列名,是否自動確認,消費方法)
        channel.basicConsume(QUEUE_INFORM_SMS,true,defaultConsumer);
    }
}

3.Routing 路由模式

生產者將訊息傳送給交換機按照路由判斷,交換機根據路由的key,只能匹配上路由key的對應的訊息佇列,對應的消費者才能消費訊息。

如上圖,rabbitMq根據對應的key,將訊息傳送到對應的佇列中,error通知將傳送到amqp.gen-S9b上,由消費者c1消費。error,info,warning通知將傳送到amqp.gen-Ag1上,由消費者c2消費。

特點:
1.每個消費者監聽自己的佇列,並且設定路由key
2.生產者將訊息傳送給交換機,由交換機根據路由key來轉發訊息到指定的佇列

生產者:

package rabbitmq.routing;

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;

/**
 * @className: Producer
 * @description: 路由模式下的生成者
 * @author: charon
 * @create: 2021-01-07 22:34
 */
public class Producer {

    /**郵件的佇列*/
    public static final String QUEUE_ROUTING_EMAIL = "queue_routing_email";

    /**簡訊的佇列*/
    public static final String QUEUE_ROUTING_SMS = "queue_routing_sms";

    /**交換機*/
    public static final String EXCHANGE_ROUTING_INFORM = "exchange_routing_inform";

    /** 設定email的路由key */
    public static final String ROUTING_EMAIL = "routing_email";

    /** 設定sms的路由key */
    public static final String ROUTING_SMS = "routing_sms";

    public static void main(String[] args) {
        // 建立連線工廠
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 設定ip,埠,因為是本機,所以直接設定為127.0.0.1
        connectionFactory.setHost("127.0.0.1");
        // web埠預設為15672,通訊埠為5672
        connectionFactory.setPort(5672);
        // 設定使用者名稱和密碼
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        // 設定虛擬ip,預設為/,一個rabbitmq的服務可以設定多個虛擬機器,每個虛擬機器就相當於一個獨立的mq
        connectionFactory.setVirtualHost("/");
        Connection connection = null;
        Channel channel = null;
        try {
            connection = connectionFactory.newConnection();
            // 建立通道
            channel = connection.createChannel();
            // 宣告佇列(佇列名稱,是否持久化,是否排它,是否自動刪除,佇列的擴充套件引數比如設定存活時間等)
            channel.queueDeclare(QUEUE_ROUTING_EMAIL, true, false, false, null);
            channel.queueDeclare(QUEUE_ROUTING_SMS, true, false, false, null);
            // 交換機(交換機名稱,交換機型別(fanout:釋出訂閱,direct:routing,topic:主題,headers:header模式))
            channel.exchangeDeclare(EXCHANGE_ROUTING_INFORM, BuiltinExchangeType.DIRECT);
            // 繫結交換機(佇列名稱,交換機名稱,routingKey)
            channel.queueBind(QUEUE_ROUTING_EMAIL,EXCHANGE_ROUTING_INFORM,ROUTING_EMAIL);
            channel.queueBind(QUEUE_ROUTING_SMS,EXCHANGE_ROUTING_INFORM,ROUTING_SMS);
            // 傳送多條訊息
            for (int i = 0; i < 5; i++) {
                String message = "hello charon good evening by routing --email";
                // 指定交換機(交換機,RoutingKey,額外的訊息屬性,訊息內容)
                channel.basicPublish(EXCHANGE_ROUTING_INFORM, ROUTING_EMAIL, null, message.getBytes());
                System.out.println("傳送訊息給mq:" + message);
            }
            // 傳送多條訊息
            for (int i = 0; i < 5; i++) {
                String message = "hello charon good evening by routing --sms";
                // 指定交換機(交換機,RoutingKey,額外的訊息屬性,訊息內容)
                channel.basicPublish(EXCHANGE_ROUTING_INFORM, ROUTING_SMS, null, message.getBytes());
                System.out.println("傳送訊息給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();
            }
        }
    }
}

消費email的消費者:

package rabbitmq.routing;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @className: EmailConsumer
 * @description: 路由模式下的email消費者
 * @author: charon
 * @create: 2021-01-07 22:40
 */
public class EmailConsumer {
    /**郵件的佇列*/
    public static final String QUEUE_ROUTING_EMAIL = "queue_routing_email";

    /**交換機*/
    public static final String EXCHANGE_ROUTING_INFORM = "exchange_routing_inform";

    /** 設定email的路由key */
    public static final String ROUTING_EMAIL = "routing_email";

    public static void main(String[] args) throws IOException, TimeoutException {
        // 建立連線工廠
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 設定ip,埠,因為是本機,所以直接設定為127.0.0.1
        connectionFactory.setHost("127.0.0.1");
        // web埠預設為15672,通訊埠為5672
        connectionFactory.setPort(5672);
        // 設定使用者名稱和密碼
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        // 設定虛擬ip,預設為/,一個rabbitmq的服務可以設定多個虛擬機器,每個虛擬機器就相當於一個獨立的mq
        connectionFactory.setVirtualHost("/");
        Connection connection = connectionFactory.newConnection();
        // 建立通道
        Channel channel = connection.createChannel();
        // 宣告佇列(佇列名稱,是否持久化,是否排它,是否自動刪除,佇列的擴充套件引數比如設定存活時間等)
        channel.queueDeclare(QUEUE_ROUTING_EMAIL, true, false, false, null);
        channel.exchangeDeclare(EXCHANGE_ROUTING_INFORM, BuiltinExchangeType.DIRECT);
        // 繫結佇列並指明路由key
        channel.queueBind(QUEUE_ROUTING_EMAIL,EXCHANGE_ROUTING_INFORM,ROUTING_EMAIL);
        // 實現消費方法
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
            /**
             *
             * @param consumerTag 消費者標籤
             * @param envelope 信封,可以獲取交換機等資訊
             * @param properties 訊息屬性
             * @param body 消費內容,位元組陣列,可以轉成字串
             * @throws IOException
             */
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message = new String(body,"utf-8");
                System.out.println("收到的email訊息是:"+message);
            }
        };
        // 消費訊息(佇列名,是否自動確認,消費方法)
        channel.basicConsume(QUEUE_ROUTING_EMAIL,true,defaultConsumer);
    }
}

消費簡訊的消費者:

package rabbitmq.routing;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
 * @className: EmailConsumer
 * @description: 路由模式下的email消費者
 * @author: charon
 * @create: 2021-01-07 22:40
 */
public class SmsConsumer {
    /**郵件的佇列*/
    public static final String QUEUE_ROUTING_SMS = "queue_routing_sms";

    /**交換機*/
    public static final String EXCHANGE_ROUTING_INFORM = "exchange_routing_inform";

    /** 設定email的路由key */
    public static final String ROUTING_SMS = "routing_sms";

    public static void main(String[] args) throws IOException, TimeoutException {
        // 建立連線工廠
        ConnectionFactory connectionFactory = new ConnectionFactory();
        // 設定ip,埠,因為是本機,所以直接設定為127.0.0.1
        connectionFactory.setHost("127.0.0.1");
        // web埠預設為15672,通訊埠為5672
        connectionFactory.setPort(5672);
        // 設定使用者名稱和密碼
        connectionFactory.setUsername("guest");
        connectionFactory.setPassword("guest");
        // 設定虛擬ip,預設為/,一個rabbitmq的服務可以設定多個虛擬機器,每個虛擬機器就相當於一個獨立的mq
        connectionFactory.setVirtualHost("/");
        Connection connection = connectionFactory.newConnection();
        // 建立通道
        Channel channel = connection.createChannel();
        // 宣告佇列(佇列名稱,是否持久化,是否排它,是否自動刪除,佇列的擴充套件引數比如設定存活時間等)
        channel.queueDeclare(QUEUE_ROUTING_SMS, true, false, false, null);
        channel.exchangeDeclare(EXCHANGE_ROUTING_INFORM, BuiltinExchangeType.DIRECT);
        // 繫結佇列並指明路由key
        channel.queueBind(QUEUE_ROUTING_SMS,EXCHANGE_ROUTING_INFORM,ROUTING_SMS);
        // 實現消費方法
        DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
            /**
             *
             * @param consumerTag 消費者標籤
             * @param envelope 信封,可以獲取交換機等資訊
             * @param properties 訊息屬性
             * @param body 消費內容,位元組陣列,可以轉成字串
             * @throws IOException
             */
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                String message = new String(body,"utf-8");
                System.out.println("收到的簡訊訊息是:"+message);
            }
        };
        // 消費訊息(佇列名,是否自動確認,消費方法)
        channel.basicConsume(QUEUE_ROUTING_SMS,true,defaultConsumer);
    }
}

4.Topic 主題模式

  1. 星號井號代表萬用字元
  2. 星號代表一個單詞,井號代表一個或多個單詞
  3. 路由功能新增模糊匹配
  4. 訊息產生者產生訊息,把訊息交給交換機
  5. 交換機根據key的規則模糊匹配到對應的佇列,由佇列的監聽消費者接收訊息消費

特點:
1.每個消費者監聽自己的佇列,並且設定帶萬用字元的routingkey
2.生產者將訊息傳送給broker,由交換機及根據路由key來轉發訊息到指定的佇列

5.Header 轉發器

取消了路由key,使用header中的key/value(鍵值對)來匹配佇列。

6.RPC 遠端呼叫

基於direct型別交換機實現。生產者將訊息遠端傳送給rpc佇列,消費者監聽rpc訊息佇列的訊息並訊息,然後將返回結果放入到響應佇列中,生產者監聽響應佇列中的訊息,拿到消費者的處理結果,實現遠端RPC遠端呼叫。

參考檔案:

https://www.cnblogs.com/Jeely/p/10784013.html
https://lovnx.blog.csdn.net/article/details/70991021

相關文章