rabbitmq-交換機的基本使用

之前生產者的消息是發個一個消費者的,如果想多個消費者都收到消息(系統告知所有用戶今天促銷)就需要使用rabbitmq中交換機(Exchange)功能了。

簡示圖:

代碼:

import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

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

/**
 * 生產者
 * 訂閱模式 Publish/Subscribe
 * 通過交換機把消息發送給所有綁定該交換機的隊列
 * Created by py
 * 2020/4/20
 */
public class SendRabbit {
    private static String exchange = "test_exchange_fanout";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        //確認每次只發送一條信息
        channel.basicQos(1);
        //聲明一個交換機,該類型交換機對生產者的消息不做任何處理,所有綁定該交換機的隊列都會收到生產者的消息
        channel.exchangeDeclare(exchange,"fanout");
        for (int i = 0; i < 50; i++) {
            String msg = "This is test_exchange_fanout:"+i;
            /**
             * basicPublish(String exchange, String routingKey, AMQP.BasicProperties props, byte[] body)
             * exchange:交換機名稱
             * routingKey:隊列綁定的交換機的key:不指定的時候所有綁定該交換機的隊列都能收到消息
             * body: 信息載體
             */
            channel.basicPublish(exchange,"",null,msg.getBytes());
        }
        System.out.println("發送完成");
        channel.close();
        instance.close();
    }
}
import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.*;

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

/**
 * 消費者1
 * Created by py
 * 2020/4/20
 */
public class FristConsumer {
    private static String exchange = "test_exchange_fanout";
    private static String queue = "test_exchange_fanout_queue1";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        channel.basicQos(1);
        //設置讓rabbit消息持久化
        boolean durable = true;
        channel.queueDeclare(queue,durable,false,false,null);
        channel.queueBind(queue,exchange,"");
        // 定義一個消費者
        Consumer consumer = new DefaultConsumer(channel) {
            // 消息到達 觸發這個方法
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                try {
                    String msg = new String(body,"utf-8");
                    System.out.println("FristConsumer:"+msg);
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };
        boolean autoAck = false;
        channel.basicConsume(queue, autoAck, consumer);
    }
}
/**
 * 消費者2
 * Created by py
 * 2020/4/20
 */
public class SecondConsumer {
    private static String exchange = "test_exchange_fanout";
    private static String queue = "test_exchange_fanout_queue2";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        channel.basicQos(1);
        //設置讓rabbit消息持久化
        boolean durable = true;
        channel.queueDeclare(queue,durable,false,false,null);
        channel.queueBind(queue,exchange,"");
        // 定義一個消費者
        Consumer consumer = new DefaultConsumer(channel) {
            // 消息到達 觸發這個方法
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                try {
                    String msg = new String(body,"utf-8");
                    System.out.println("SecondConsumer:"+msg);
                    Thread.sleep(1500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };
        boolean autoAck = false;
        channel.basicConsume(queue, autoAck, consumer);
    }
}

PS:生產者將消息發送到交換機中,哪個消費者的隊列綁定了這個交換機,就把消息發送到哪個隊列,這樣一個消息就會發送個不同的隊列讓多個消費者接收到了。
fanout:交換機的類型,該類型時所有綁定該交換機的隊列都會收到該交換機發出的消息
channel.exchangeDeclare(exchange,"fanout");

QA:若想生產者第一條消息消費者都能接收,第二條消息只讓部分消費者接收,應該如何實現?

此時需要使用Exchange的另一種類型:direct,同時隊列與交換機使用routingKey進行綁定。

簡示圖:

此時生產者向exchange推送消息時指定發送給哪個routingKey所綁定的隊列。
如指定發送個routingA綁定的隊列時兩個服務都能收到消息,發送消息給routingC綁定的隊列時則只有服務B能收到消息。

/**
 * 生產者
 * 路由模式
 * 交換機的信息發送到指定的key,隊列綁定交換機的時候指定的該key才能收到信息
 * Created by py
 * 2020/4/20
 */
public class SendRabbit {
    private static String exchange = "test_exchange_direct";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        //確認每次只發送一條信息
        //prefetchSize:設置傳輸過來的消息的大小
        //prefetchCount:一次傳輸多少消息
        //global:是否是全局消息,true:整個channel都使用該設置,false只應用於當前的customer
        //PS:global:目前設置爲false;
        channel.basicQos(1);
        //聲明一個交換機,該類型交換機對生產者的消息進行處理,綁定該交換機的隊列中存在和交換機發送信息時使用的key的隊列才能收到信息
        //交換機名稱,交換機類型,是否持久化:消息未完成消費時是否寫到磁盤裏防止數據丟失
        channel.exchangeDeclare(exchange,"direct",true);
        for (int i = 0; i < 50; i++) {
            String msg = "This is test_exchange_direct:"+i;
            /**
             * basicPublish(String exchange, String routingKey, AMQP.BasicProperties props, byte[] body)
             * exchange:交換機名稱
             * routingKey:隊列綁定的交換機的key:指定的時候那個隊列有這個key哪個隊列就會收到交換機的信息
             * body: 信息載體
             */
            //todo routingKey:rabbit==》兩個隊列都綁定了rabbit所以交換機的信息兩個隊列都能收到
            channel.basicPublish(exchange,"rabbit",null,msg.getBytes());
            //todo routingKey:monkey==》隊列2綁定了monkey所以交換機的信息只有隊列2能收到
            //channel.basicPublish(exchange,"monkey",null,msg.getBytes());
        }
        System.out.println("發送完成");
        channel.close();
        instance.close();
    }
}
import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.*;

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

/**
 * 消費者1
 * Created by py
 * 2020/4/20
 */
public class FristConsumer {
    private static String exchange = "test_exchange_direct";
    private static String queue = "test_exchange_direct_queue1";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        channel.basicQos(1);
        //設置讓rabbit消息持久化
        boolean durable = true;
        channel.queueDeclare(queue,durable,false,false,null);
        //rabbit:綁定的路由key
        channel.queueBind(queue,exchange,"rabbit");
        //定義一個消費者
        Consumer consumer = new DefaultConsumer(channel) {
            //消息到達 觸發這個方法
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                try {
                    String msg = new String(body,"utf-8");
                    System.out.println("FristConsumer:"+msg);
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };
        boolean autoAck = false;
        channel.basicConsume(queue, autoAck, consumer);
    }
}
import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.*;

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

/**
 * 消費者2
 * Created by py
 * 2020/4/20
 */
public class SecondConsumer {
    private static String exchange = "test_exchange_direct";
    private static String queue = "test_exchange_direct_queue2";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        channel.basicQos(1);
        //設置讓rabbit消息持久化
        boolean durable = true;
        channel.queueDeclare(queue,durable,false,false,null);
        channel.queueBind(queue,exchange,"rabbit");
        channel.queueBind(queue,exchange,"cat");
        channel.queueBind(queue,exchange,"dog");
        channel.queueBind(queue,exchange,"bird");
        channel.queueBind(queue,exchange,"monkey");
        // 定義一個消費者
        Consumer consumer = new DefaultConsumer(channel) {
            // 消息到達 觸發這個方法
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                try {
                    String msg = new String(body,"utf-8");
                    System.out.println("SecondConsumer:"+msg);
                    Thread.sleep(300);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };
        boolean autoAck = false;
        channel.basicConsume(queue, autoAck, consumer);
    }
}
//將交換機和隊列通過routingKey:rabbit進行綁定 ==》隊列和交換機之間可綁定多個routingKey
channel.queueBind(queue,exchange,"rabbit");
PS:生產者發送消息時寫的routingKey要和消費者綁定的routingKey完全一致,才能接收到消息

QA:每個routingKey都要完全一致,假設服務A是訂單模塊,服務B是庫存模塊,那按照上述的方式我們要綁定海量的routingKey纔可以,直接增大了開發量和業務的複雜性,如何簡化這樣的模式呢?
使用Exchangetopic模式,topic主要是實現對routingKey的模糊匹配,從而更加靈活的指定我們的消息發送給哪臺服務器。
簡示圖:

#:表示0個或多個  
例:服務A推送信息的routingKey
order.delete.yesterday  queueB可以接收
order.list  可以接收  queueB可以接收

*:表示一個
warehouse.query   queueA可以接收
warehouse.delete.yesterday    queueA無法接收

服務A發送信息推送至routingA 時,隊列queueA和隊列queueB都可以接收到信息

import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

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

/**
 * 生產者
 * Topic Exchange
 * 此時隊列需要綁定要一個模式上。
 * 符號“#”匹配一個或多個詞,符號“*”匹配一個詞。
 * 因此“audit.#”能夠匹配到“audit.irs.corporate”
 * 但是“audit.*” 只會匹配到“audit.irs”。
 * Created by py
 * 2020/4/20
 */
public class SendRabbit {
    private static String exchange = "test_exchange_topic";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        //確認每次只發送一條信息
        channel.basicQos(1);
        //聲明一個交換機,隊列中的key可以和交換機發送信息的key進行匹配時就能收到消息
        channel.exchangeDeclare(exchange,"topic",true);

            String msg = "This is test_exchange_topic";
            /**
             * basicPublish(String exchange, String routingKey, AMQP.BasicProperties props, byte[] body)
             * exchange:交換機名稱
             * routingKey:隊列綁定的交換機的key:指定的時候那個隊列有這個key哪個隊列就會收到交換機的信息
             * body: 信息載體
             * */

            //todo routingKey:rabbit==》兩個隊列都綁定了rabbit所以交換機的信息兩個隊列都能收到
            channel.basicPublish(exchange,"order.aaa.bbb",null,msg.getBytes());


        System.out.println("發送完成");
        channel.close();
        instance.close();
    }
}
import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.*;

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

/**
 * 消費者1
 * Created by py
 * 2020/4/20
 */
public class FristConsumer {

    private static String exchange = "test_exchange_topic";
    private static String queue = "test_exchange_topic_queue1";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        channel.basicQos(1);
        //設置讓rabbit消息持久化
        boolean durable = true;
        channel.queueDeclare(queue,durable,false,false,null);
        channel.queueBind(queue,exchange,"order.list");
        channel.queueBind(queue,exchange,"order.add");
        channel.queueBind(queue,exchange,"order.#");
        channel.queueBind(queue,exchange,"audit.*");
        //定義一個消費者
        Consumer consumer = new DefaultConsumer(channel) {
            //消息到達 觸發這個方法
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                try {
                    String msg = new String(body,"utf-8");
                    System.out.println("FristConsumer:"+msg);
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };
        boolean autoAck = false;
        channel.basicConsume(queue, autoAck, consumer);
    }
}
import com.example.springcloud.eurekaclinet1demo.uitl.RabbitUtils;
import com.rabbitmq.client.*;

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

/**
 * 消費者2
 * Created by py
 * 2020/4/20
 */
public class SecondConsumer {
    private static String exchange = "test_exchange_topic";
    private static String queue = "test_exchange_topic_queue2";
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection instance = RabbitUtils.getInstance();
        Channel channel = instance.createChannel();
        channel.basicQos(1);
        //設置讓rabbit消息持久化
        boolean durable = true;
        channel.queueDeclare(queue,durable,false,false,null);
        channel.queueBind(queue,exchange,"order.del");
        channel.queueBind(queue,exchange,"audit.#");
        channel.queueBind(queue,exchange,"order.*");
        //定義一個消費者
        Consumer consumer = new DefaultConsumer(channel) {
            //消息到達 觸發這個方法
            @Override
            public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
                super.handleDelivery(consumerTag, envelope, properties, body);
                try {
                    String msg = new String(body,"utf-8");
                    System.out.println("SecondConsumer:"+msg);
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    channel.basicAck(envelope.getDeliveryTag(),false);
                }
            }
        };
        boolean autoAck = false;
        channel.basicConsume(queue, autoAck, consumer);
    }
}

 

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