RabbitMQ学习(七)—主题模式及work模式的入门案例

一、主题模式—>topic

主题模式与路由模式相似,但是,主题模式是一种模糊的匹配方式。交换机为topic模式,路由key可选 *(匹配明确的一个单词) 或 #(匹配0到多个单词).其路由的*和#类似于数据库中的模糊匹配。设置模糊的绑定方式,“*”操作符将“.”视为分隔符,匹配单个字符;“#”操作符没有分块的概念,它将任意“.”均视为关键字的匹配部分,能够匹配多个字符。 比如路由key为*.s.*只能接收com.s.com这样形式的队列消息,*是指有且只能有一个;#.s.#可以接收com.s.som、s.com、com.s、s、com.com.s.com.com等。

主题模式的生产者代码如下:

public class Producer {
    public static void main(String[] args) throws IOException, TimeoutException {
        //所有的中间件技术都是基于tcp/ip协议基础之上构建新的协议规范,只不过rabbitmq遵循的是amqp
        //1.创建连接工程
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("ip");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("admin");
        connectionFactory.setPassword("admin");
        connectionFactory.setVirtualHost("/");
        Connection connection = null;
        Channel channel = null;
        try {
            //创建连接Connection
            connection = connectionFactory.newConnection("生产者");
            //通过连接获取通道Channel
            channel = connection.createChannel();
            //创建交换机
            String exchangeName = "direct_msg_topic";
            //设置交换机类型
            String exchangeType = "topic";
            //声明交换机  参数1:交换机名字 参数2:交换机类型 参数3:交换机是否持久化
            channel.exchangeDeclare(exchangeName, exchangeType, true);
            //声明队列名字
            String queueName1 = "queue4";
            String queueName2 = "queue5";
            String queueName3 = "queue6";
            /*
             *创建队列
             *参数1:  队列名称 如果队列不存在自动创建
             *参数2:  用来定义队列特性是否要持久化 true 持久化队列   false 不持久化(服务重启后队列还保存,但不保存消息)
             *参数3:  exclusive 是否独占队列  true 独占队列   false  不独占
             *参数4:  autoDelete: 是否在消费完成后自动删除队列  true 自动删除  false 不自动删除
             *参数5:  额外附加参数
             */
            channel.queueDeclare(queueName1, true, false, false, null);
            channel.queueDeclare(queueName2, true, false, false, null);
            channel.queueDeclare(queueName3, true, false, false, null);
            //绑定队列和交换机 参数1:队列名字 参数2:交换机名字 参数3:路由key
            channel.queueBind(queueName1, exchangeName, "*.s.*");
            channel.queueBind(queueName2, exchangeName, "#.s.#");
            channel.queueBind(queueName3, exchangeName, "*.s");
            Scanner sc = new Scanner(System.in);

                //准备消息内容
               String message ="hello,s2";
                //发送消息给队列queue
                channel.basicPublish(exchangeName, "com.s.rabbitmq", null, message.getBytes());
                System.out.println("发送成功!");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        } finally {
            //7.关闭连接
//            if (channel!=null&&channel.isOpen()){
//                channel.close();
//            }
//            if (connection!=null&& connection.isOpen()){
//                connection.close();
//            }
            //8.关闭通道
        }

    }
}

路由模式消费者代码如下:

public class Consumer {
    public static Runnable runnable = new Runnable() {
        @Override
        public void run() {
            //创建工厂
            ConnectionFactory factory = new ConnectionFactory();
            //连接
            factory.setHost("ip");
            factory.setPort(5672);
            factory.setVirtualHost("/");
            factory.setUsername("admin");
            factory.setPassword("admin");
            //获取队列名称
            final String queueName = Thread.currentThread().getName();
            Connection connection = null;
            Channel channel = null;
            try {
                //获取连接
                connection = factory.newConnection("消费者");
                //从连接中获取通道
                channel = connection.createChannel();
                //定义接收消息回调
                channel.basicConsume(queueName, true, new DeliverCallback() {
                    @Override
                    public void handle(String s, Delivery delivery) throws IOException {
                        System.out.println(delivery.getEnvelope().getDeliveryTag());
                        System.out.println(queueName + ":收到消息:" + new String(delivery.getBody(), "UTF-8"));
                    }
                }, new CancelCallback() {
                    @Override
                    public void handle(String s) throws IOException {
                        System.out.println("接收失败了。。。。");
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    };

    public static void main(String[] args) {
        new Thread(runnable, "queue4").start();
        new Thread(runnable, "queue5").start();
        new Thread(runnable, "queue6").start();
    }
}

在代码中,用三个不同的路由key去绑定交换机和队列:*.s.*  ; #.s.#  ; *.s。运行生产者代码后,在图形管理界面会生产一个direct_msg_topic交换机,其类型为topic,并且绑定了不同路由key的队列4、5、6。然后发送一条路由key为com.s.rabbit的消息给队列。发送成功后,根据匹配规则只有队列4、5是可以接收到消息的。在图形管理界面查看,的确如此。启动消费者代码,在消费者中只有队列4、5得到消息。

 

 

 

 

 现在将生产者代码中的发送消息给队列的路由key改为s.rabbit,然后运行生产者代码,可以在图形界面看到只有队列5、6存储了一条信息;运行消费者代码,只有队列5、6接收到信息。

 

  现在将生产者代码中的发送消息给队列的路由key改为s,然后运行生产者代码,可以在图形界面看到只有队列5存储了一条信息;运行消费者代码,只有队列5接收到信息

 

二、work模式 

1、轮询模式

轮询分发就是将消息队列中的消息,依次发送给所有消费者。一个消息只能被一个消费者获取。

生产者代码如下:

public class Producer {
    public static void main(String[] args) throws IOException, TimeoutException {
        //所有的中间件技术都是基于tcp/ip协议基础之上构建新的协议规范,只不过rabbitmq遵循的是amqp
        //1.创建连接工程
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("ip");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("admin");
        connectionFactory.setPassword("admin");
        connectionFactory.setVirtualHost("/");
        Connection connection = null;
        Channel channel = null;
        try {
            //创建连接Connection
            connection = connectionFactory.newConnection("生产者");
            //通过连接获取通道Channel
            channel = connection.createChannel();
            for(int i=1;i<+20;i++){
                //准备消息内容
               String message =""+i;
                //发送消息给队列queue
            channel.basicPublish(“queue7”,null,message.getBytes());
         }
                System.out.println("发送成功!");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        } finally {
            //7.关闭连接
//            if (channel!=null&&channel.isOpen()){
//                channel.close();
//            }
//            if (connection!=null&& connection.isOpen()){
//                connection.close();
//            }
            //8.关闭通道
        }

    }
}

 消费者1代码如下:

public class Consumer {
    public static void main(String[] args) {
      
            //创建工厂
            ConnectionFactory factory = new ConnectionFactory();
            //连接
            factory.setHost("ip");
            factory.setPort(5672);
            factory.setVirtualHost("/");
            factory.setUsername("admin");
            factory.setPassword("admin");
            //获取队列名称
            final String queueName = Thread.currentThread().getName();
            Connection connection = null;
            Channel channel = null;
            try {
                //获取连接
                connection = factory.newConnection("消费者1");
                //从连接中获取通道
                channel = connection.createChannel();
                //定义接收消息回调
                channel.basicConsume(queueName, true, new DeliverCallback() {
                    @Override
                    public void handle(String s, Delivery delivery) throws IOException {
                        System.out.println(delivery.getEnvelope().getDeliveryTag());
                        System.out.println(new String(delivery.getBody(), "UTF-8"));
                    }
                }, new CancelCallback() {
                    @Override
                    public void handle(String s) throws IOException {
                        System.out.println("接收失败了。。。。");
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }

        } 
       
    }
}

消费者2代码同消费者1的代码。

运行生产者和消费者1、2 的代码后,

消费者1输出:

1 3 5 7 9 11 13 15 17 19

消费者2输出:

2 4 6 8 10 12 14 16 18 20

这就是轮询分发,一人一条。

2、公平分发

消费者设置每次从队列里取出一条数据,并且关闭自动回复机制,每次取出一条数据,手动回复并继续取下一条数据。

生产者代码如下

public class Producer {
    public static void main(String[] args) throws IOException, TimeoutException {
        //所有的中间件技术都是基于tcp/ip协议基础之上构建新的协议规范,只不过rabbitmq遵循的是amqp
        //1.创建连接工程
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("ip");
        connectionFactory.setPort(5672);
        connectionFactory.setUsername("admin");
        connectionFactory.setPassword("admin");
        connectionFactory.setVirtualHost("/");
        Connection connection = null;
        Channel channel = null;
        try {
            //创建连接Connection
            connection = connectionFactory.newConnection("生产者");
            //通过连接获取通道Channel
            channel = connection.createChannel();
            for(int i=1;i<+20;i++){
                //准备消息内容
               String message ="i";
                //发送消息给队列queue
            channel.basicPublish(“queue7”,null,message.getBytes());
         }
                System.out.println("发送成功!");
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
        } finally {
            //7.关闭连接
//            if (channel!=null&&channel.isOpen()){
//                channel.close();
//            }
//            if (connection!=null&& connection.isOpen()){
//                connection.close();
//            }
            //8.关闭通道
        }

    }
}

消费者1、2代码如下

public class Consumer1 {
    public static void main(String[] args) {
      
            //创建工厂
            ConnectionFactory factory = new ConnectionFactory();
            //连接
            factory.setHost("ip");
            factory.setPort(5672);
            factory.setVirtualHost("/");
            factory.setUsername("admin");
            factory.setPassword("admin");
            //获取队列名称
            final String queueName = Thread.currentThread().getName();
            Connection connection = null;
            Channel channel = null;
            try {
                //获取连接
                connection = factory.newConnection("消费者2");
                //从连接中获取通道
                channel = connection.createChannel();
                //每次只向队列取一条消息
                channel.basicQos(1);
                //定义接收消息回调
                channel.basicConsume(queueName, false, new DeliverCallback() {
                    @Override
                    public void handle(String s, Delivery delivery) throws IOException {
                
                       System.out.println(new String(delivery.getBody(), "UTF-8"));
                        
                        //手动应答
                        channal.basicACK(delivery.Envelope().getDeliveryTag(), false);
                    
                    }
                }, new CancelCallback() {
                    @Override
                    public void handle(String s) throws IOException {
                        System.out.println("接收失败了。。。。");
                    }
                });
            } catch (Exception e) {
                            }

        } 
       
    }
}

消费者2代码如下:

public class Consumer2 {
    public static void main(String[] args) {
      
            //创建工厂
            ConnectionFactory factory = new ConnectionFactory();
            //连接
            factory.setHost("ip");
            factory.setPort(5672);
            factory.setVirtualHost("/");
            factory.setUsername("admin");
            factory.setPassword("admin");
            //获取队列名称
            final String queueName = Thread.currentThread().getName();
            Connection connection = null;
            Channel channel = null;
            try {
                //获取连接
                connection = factory.newConnection("消费者2");
                //从连接中获取通道
                channel = connection.createChannel();
                //每次只向队列取一条消息
                channel.basicQos(1);
                //定义接收消息回调
                channel.basicConsume(queueName, false, new DeliverCallback() {
                    @Override
                    public void handle(String s, Delivery delivery) throws IOException {
                System.out.println(new String(delivery.getBody(), "UTF-8"));
                        //消费者休息2s处理业务
                        Thread.sleep(2000);
                        //手动应答
                        channal.basicACK(delivery.Envelope().getDeliveryTag(), false);
                    
                    }
                }, new CancelCallback() {
                    @Override
                    public void handle(String s) throws IOException {
                        System.out.println("接收失败了。。。。");
                    }
                });
            } catch (Exception e) {
                            }

        } 
       
    }
}

运行生产者和消费者1、2的代码后

消费者1会输出:

1 2  3 4 6 7 8 9 11 12 13 14 16 17 18 19 20

消费者2 会输出:5 10 15

这就是公平分发,能者多劳

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值