• 消息队列 (3) RabbtMQ 发布/订阅 、Routing Key 模式、Topic 通配符模式


    第三种模式:发布/订阅 一对多 每个消费者监听各自的队列 消息来了每个一个消费者 都可以收到

    在订阅模式中,多了一个交换机 Exchange角色,而且过程略有变化。

    P:生产者,发送消息的程序,但是不再发送到队列中,而是发给交换机。

    Queue:消息队列,接收消息、缓存消息。

    Exchange:交换机,一方面接收生产者发送来的消息。另一方面知道如何处理消息,例如交给特别的队列,或者全部的队列,或者将消息丢弃。到底如何操作取决于Exchange是哪种类型:

      1.Fanout:广播,将消息分发给所有绑定到交换机的队列。 

      2.Direct:定向,把消息交给符合特定routing key 的队列。

      3.Topic:通配符,吧消息交给符合routing pattern (路由模式)的队列。

    Exchange 只负责转发消息,不具备存储消息的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息就会丢失!

    一、编写代码:

    发布方: fanout 分发消息

    package com.david;
    
    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 Publish {
        private static String EXCHANGE_NAME = "pubsub";
        public static void main(String[] args) throws IOException, TimeoutException {
            //创建连接工厂
            ConnectionFactory factory = new ConnectionFactory();
            //设置参数
            factory.setHost("10.211.55.4"); //id
            factory.setVirtualHost("local"); //虚拟机
            factory.setPort(5672); //端口 默认5672
            factory.setUsername("admin");
            factory.setPassword("admin");
            //创建connect
            Connection connection = factory.newConnection();
            //创建管道
            Channel channel = connection.createChannel();
    
    
            //创建交换机 fanout是分发 所有人都收到
            //channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
            channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
    
            //创建队列
            String queue1_name="test_fanout_queue1";
            String queue2_name="test_fanout_queue2";
            channel.queueDeclare(queue1_name,true,false,false,null);
            channel.queueDeclare(queue2_name,true,false,false,null);
    
            //绑定交换机
            channel.queueBind(queue1_name,EXCHANGE_NAME,"");
            channel.queueBind(queue2_name,EXCHANGE_NAME,"");
    
    
            for(int i = 0;i<10;i++){
                String message = "hello rabbitmq!" + i;
                channel.basicPublish(EXCHANGE_NAME,"",null,message.getBytes());
                System.out.println("Producer Send : " + message);
            }
    
            channel.close();
            connection.close();
        }
    }

    消费者代码

    import com.rabbitmq.client.*;
    
    import java.io.IOException;
    import java.util.concurrent.TimeoutException;
    
    public class Sub1 {
    
        private static String QUEUE_NAME = "test_fanout_queue1";
        public static void main(String[] args) throws IOException, TimeoutException {
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("10.211.55.4");
            factory.setUsername("admin");
            factory.setPassword("admin");
            factory.setPort(5672);
            factory.setVirtualHost("local");
    
            Connection connection = factory.newConnection();
    
            final Channel channel = connection.createChannel();
    
            channel.queueDeclare(QUEUE_NAME,true,false,false,null);
    
            System.out.println("work1 ready");
    
            //每次从队列获取的数量
            channel.basicQos(1);
    
    
            Consumer comsumer = new DefaultConsumer(channel){
                @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("work1 收到了 :" + message);
                    try {
                        doWork();
                    }catch (Exception ex){
                        channel.abort();
                    }finally {
                        System.out.println("work1 完成了");
                        channel.basicAck(envelope.getDeliveryTag(),false);
                    }
                }
            };
    
            boolean autoAck = false;
    
            channel.basicConsume(QUEUE_NAME,autoAck,comsumer);
    
        }
    
        public static void doWork() throws InterruptedException {
            Thread.sleep(1000);
        }
    }

    上面完成了一个发布/订阅模式的消息队列  可以看到 当发布一个消息的时候 发送到交换机中 由交换机发送给每一个消费者 没有竞争 都得到了

    第四种模式:Routing 路由模式

      上面我们采用了广播的模式进行消息的发送,现在我们采用路由的方式对不同的消息进行过滤。

    新建发送端

     1 public class Producer_Routing {
     2 
     3     private static String EXCHANGE_NAME = "RoutingKey";
     4     public static void main(String[] args) throws IOException, TimeoutException {
     5         //创建连接工厂
     6         ConnectionFactory factory = new ConnectionFactory();
     7         //设置参数
     8         factory.setHost("10.211.55.4"); //id
     9         factory.setVirtualHost("local"); //虚拟机
    10         factory.setPort(5672); //端口 默认5672
    11         factory.setUsername("admin");
    12         factory.setPassword("admin");
    13         //创建connect
    14         Connection connection = factory.newConnection();
    15         //创建管道
    16         Channel channel = connection.createChannel();
    17 
    18         //创建交换机 direct
    19         channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
    20 
    21         //创建队列
    22         String queue1_name="test_direct_queue1";
    23         String queue2_name="test_direct_queue2";
    24         channel.queueDeclare(queue1_name,true,false,false,null);
    25         channel.queueDeclare(queue2_name,true,false,false,null);
    26 
    27         //队列1绑定
    28         channel.queueBind(queue1_name,EXCHANGE_NAME,"error");
    29         //队列2绑定
    30         channel.queueBind(queue2_name,EXCHANGE_NAME,"info");
    31         channel.queueBind(queue2_name,EXCHANGE_NAME,"warning");
    32         channel.queueBind(queue2_name,EXCHANGE_NAME,"error");
    33 
    34         for(int i = 0;i<10;i++){
    35             String type = "";
    36             if(i%2==0){
    37                 type = "info";
    38             }else{
    39                 type = "error";
    40             }
    41             String message = type + i;
    42             channel.basicPublish(EXCHANGE_NAME,type,null,message.getBytes());
    43             System.out.println("Producer Send : " + message);
    44         }
    45 
    46         channel.close();
    47         connection.close();
    48 
    49     }
    50 }

    新建消费者1 用于接受error

    public class Customer_RoutingKey1 {
        private static String QUEUE_NAME = "test_direct_queue1";
        public static void main(String[] args) throws IOException, TimeoutException {
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("10.211.55.4");
            factory.setUsername("admin");
            factory.setPassword("admin");
            factory.setPort(5672);
            factory.setVirtualHost("local");
    
            Connection connection = factory.newConnection();
    
            final Channel channel = connection.createChannel();
    
            channel.queueDeclare(QUEUE_NAME,true,false,false,null);
    
            System.out.println("routing1 ready");
    
            Consumer comsumer = new DefaultConsumer(channel){
                @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("routing1 收到了 :" + message);
                }
            };
            channel.basicConsume(QUEUE_NAME,true,comsumer);
    
        }
    
    }

    新建消费者2 用于接受info

    public class Customer_RoutingKey2 {
        private static String QUEUE_NAME = "test_direct_queue2";
        public static void main(String[] args) throws IOException, TimeoutException {
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("10.211.55.4");
            factory.setUsername("admin");
            factory.setPassword("admin");
            factory.setPort(5672);
            factory.setVirtualHost("local");
    
            Connection connection = factory.newConnection();
    
            final Channel channel = connection.createChannel();
    
            channel.queueDeclare(QUEUE_NAME,true,false,false,null);
    
            System.out.println("routing2 ready");
    
            Consumer comsumer = new DefaultConsumer(channel){
                @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("routing2 收到了 :" + message);
                }
            };
            channel.basicConsume(QUEUE_NAME,true,comsumer);
    
        }
    }

    执行后 只有routingkey1 灰收到 1 3 5 7 9  routingkey2 可以收到全部

    第五种模式:通配符模式 Topics

    这种应该属于模糊匹配

    *:可以替代一个词

    #:可以替代0或者多个词

    发送端:

    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 TopicSend {
        private static final String EXCHANGE_NAME = "topic_logs";
    
        public static void main(String[] args) throws IOException, TimeoutException {
            Connection connection = null;
            Channel channel = null;
            try {
                ConnectionFactory factory = new ConnectionFactory();
                factory.setHost("localhost");
                connection = factory.newConnection();
                channel = connection.createChannel();
    
                //声明一个匹配模式的交换机
                channel.exchangeDeclare(EXCHANGE_NAME, "topic");
                //待发送的消息
                String[] routingKeys = new String[]{
                        "quick.orange.rabbit",
                        "lazy.orange.elephant",
                        "quick.orange.fox",
                        "lazy.brown.fox",
                        "quick.brown.fox",
                        "quick.orange.male.rabbit",
                        "lazy.orange.male.rabbit"
                };
                //发送消息
                for (String severity : routingKeys) {
                    String message = "From " + severity + " routingKey' s message!";
                    channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes());
                    System.out.println("TopicSend Sent '" + severity + "':'" + message + "'");
                }
            } catch (Exception e) {
                e.printStackTrace();
                if (connection != null) {
                    channel.close();
                    connection.close();
                }
            } finally {
                if (connection != null) {
                    channel.close();
                    connection.close();
                }
            }
        }
    }

    消费者1 匹配*.orange.*的 

    import com.rabbitmq.client.*;
    
    import java.io.IOException;
    import java.util.concurrent.TimeoutException;
    
    public class ReceiveLogsTopic1 {
        private static final String EXCHANGE_NAME = "topic_logs";
    
        public static void main(String[] args) throws IOException, TimeoutException {
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("localhost");
            Connection connection = factory.newConnection();
            Channel channel = connection.createChannel();
    
            //声明一个匹配模式的交换机
            channel.exchangeDeclare(EXCHANGE_NAME, "topic");
            String queueName = channel.queueDeclare().getQueue();
            //路由关键字
            String[] routingKeys = new String[]{"*.orange.*"};
            //绑定路由
            for (String routingKey : routingKeys) {
                channel.queueBind(queueName, EXCHANGE_NAME, routingKey);
                System.out.println("ReceiveLogsTopic1 exchange:" + EXCHANGE_NAME + ", queue:" + queueName + ", BindRoutingKey:" + routingKey);
            }
            System.out.println("ReceiveLogsTopic1 Waiting for messages");
    
            Consumer consumer = new DefaultConsumer(channel) {
                @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("ReceiveLogsTopic1 Received '" + envelope.getRoutingKey() + "':'" + message + "'");
                }
            };
            channel.basicConsume(queueName, true, consumer);
        }
    }

    消费者2 匹配*.*.rabit的 和lazy.# lazy开头的

    import com.rabbitmq.client.*;
    
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.util.concurrent.TimeoutException;
    
    public class ReceiveLogsTopic2 {
        private static final String EXCHANGE_NAME = "topic_logs";
    
        public static void main(String[] argv) throws IOException, TimeoutException {
            ConnectionFactory factory = new ConnectionFactory();
            factory.setHost("localhost");
            Connection connection = factory.newConnection();
            Channel channel = connection.createChannel();
    //      声明一个匹配模式的交换器
            channel.exchangeDeclare(EXCHANGE_NAME, "topic");
            String queueName = channel.queueDeclare().getQueue();
            // 路由关键字
            String[] routingKeys = new String[]{"*.*.rabbit", "lazy.#"};
    //      绑定路由关键字
            for (String bindingKey : routingKeys) {
                channel.queueBind(queueName, EXCHANGE_NAME, bindingKey);
                System.out.println("ReceiveLogsTopic2 exchange:"+EXCHANGE_NAME+", queue:"+queueName+", BindRoutingKey:" + bindingKey);
            }
    
            System.out.println("ReceiveLogsTopic2 Waiting for messages");
    
            Consumer consumer = new DefaultConsumer(channel) {
                @Override
                public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws UnsupportedEncodingException {
                    String message = new String(body, "UTF-8");
                    System.out.println("ReceiveLogsTopic2 Received '" + envelope.getRoutingKey() + "':'" + message + "'");
                }
            };
            channel.basicConsume(queueName, true, consumer);
        }
    }

  • 相关阅读:
    SharedPreferences介绍,用来做数据存储
    android中的回调简单认识
    git的使用
    Android Studio插件美化Android Studio,文艺清新范
    arp欺骗技术
    进程和线程的关系
    Win下常用命令大全
    JavaWeb系列之:Servlet
    JavaWeb系列之:监听器
    JavaWeb系列之:过滤器
  • 原文地址:https://www.cnblogs.com/baidawei/p/9172464.html
Copyright © 2020-2023  润新知