记录rabbitmq工作模式之发布订阅(Publish/subscribe)

在这里插入图片描述
由图我们可以看出发布订阅的工作模式
1、一个生产者将消息发送给交换机
2、与交换机绑定的有多个队列,每个消费者监听自己的队列
3、生产者将消息发送给交换机,由交换机把消息转发到绑定次交换机的每个队列,每个绑定到交换机的队列都能接收到消息

下面来模仿现实生活中的一个案例
案例:用户通知,当用户充值成功或转账完成系统通知用户,通知方式有短信、邮件多种方法 。

1、首先创建生产者
     
     public class produce {
          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) {
                 ConnectionFactory factory = new ConnectionFactory();
                 factory.setHost("127.0.0.1");
                 factory.setPort(5672);
                 factory.setUsername("guest");
                 factory.setPassword("guest");
                 factory.setVirtualHost("/");
                 Connection connection = null;
                 Channel channel = null;
                 try {
                      connection = factory.newConnection();
                      channel = connection.createChannel();
                      //声明队列
                      channel.queueDeclare(QUEUE_INFORM_EMAIL, true, false, false, null);
                      channel.queueDeclare(QUEUE_INFORM_SMS, true, false, false, null);
                     //声明交换机
                    /**
                     *参数 String exchange, BuiltinExchangeType type
                     * 1、交换机名称
                     * 2、交换机类型
                     *    1)fanout 发布订阅模式(Publish/Subscribe)
                     *    2)direct  路由模式(Routing)
                     *    3)topic  通配符模式(topic)
                     *    4) headers 对应headers
                    */
                   channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM, BuiltinExchangeType.FANOUT);
                  //交换机和队列绑定
                  /**
                   * 参数 定String queue, String exchange, String routingKey
                   * 1、队列
                   * 2、交换机
                   * 3、路由key  交换机根据路由key把消息发送到指定队列中在发布订阅模式中设置 ""
                   */
                    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 = "测试发布订阅";
                       channel.basicPublish(EXCHANGE_FANOUT_INFORM, "", null, message.getBytes());
                     System.out.print(message);
                 }
                 } catch (Exception e) {
                         e.printStackTrace();
                 } finally {
                    //先关闭通道 再关连接
                       try {
                           channel.close();
                       } catch (Exception e) {
                           e.printStackTrace();
                      }
                     try {
                         connection.close();
                     } catch (Exception e) {
                         e.printStackTrace();
                 }
              }
         }
 }

 2、创建短信消费者
       
       public class ConsumerSendSms {
          private static final String QUEUE_INFORM_SMS = "queue_inform_sms";
          private static final String EXCHANGE_FANOUT_INFORM = "inform_exchange_fanout";

          public static void main(String[] args) throws IOException, TimeoutException {
                    ConnectionFactory factory = new ConnectionFactory();
                    factory.setHost("127.0.0.1");
                    factory.setPort(5672);
                    factory.setUsername("guest");
                    factory.setPassword("guest");
                   //rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器
                   factory.setVirtualHost("/");
                 //创建一个连接
                 Connection connection = factory.newConnection();
                 //创建与交换机的通道,每个通道代表一个会话
                 Channel channel = connection.createChannel();
                 //声明队列
                 channel.queueDeclare(QUEUE_INFORM_SMS, true, false, false, null);
                //声明交换机
                 channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM, BuiltinExchangeType.FANOUT);
                //队列与交换机绑定
                channel.queueBind(QUEUE_INFORM_SMS, EXCHANGE_FANOUT_INFORM, "");
                /**
                 * 消费者接收消息调用此方法
                 */
                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 {
                 //交换机
                  envelope.getExchange();
                 //消息id mq在通道中(channel)标识消息id 可用于消息已接收
                 long deliveryTag = envelope.getDeliveryTag();
                 String message = new String(body);
                 System.out.print(message);
                 }
              };
                //监听队列
              //声明队列
              /**
               *参数
               * 1、string queue
               * 2、boolean autoAck
               * 3、Consumer callback
               */
               channel.basicConsume(QUEUE_INFORM_SMS, true, defaultConsumer);
         }
     }

3、Email消费者

      public class ConsumerSendEmail {
          private static final String QUEUE_INFORM_EMAIL = "inform_queue_email";
          private static final String EXCHANGE_FANOUT_INFORM = "inform_exchange_fanout";

          public static void main(String[] args) throws IOException, TimeoutException {
                ConnectionFactory factory = new ConnectionFactory();
                factory.setHost("127.0.0.1");
                factory.setPort(5672);
                factory.setUsername("guest");
                factory.setPassword("guest");
                //rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务器
                factory.setVirtualHost("/");
                //创建一个连接
                Connection connection = factory.newConnection();
               //创建与交换机的通道,每个通道代表一个会话
               Channel channel = connection.createChannel();
               //声明队列
               channel.queueDeclare(QUEUE_INFORM_EMAIL, true, false, false, null);
               //声明交换机
               channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM, BuiltinExchangeType.FANOUT);
               //队列与交换机绑定
               channel.queueBind(QUEUE_INFORM_EMAIL, EXCHANGE_FANOUT_INFORM, "");
               /**
                * 消费者接收消息调用此方法
               */
                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 {
                  //交换机
                   envelope.getExchange();
                  //消息id mq在通道中(channel)标识消息id 可用于消息已接收
                  long deliveryTag = envelope.getDeliveryTag();
                 String message = new String(body);
                 System.out.print(message);
                  }
                };
              //监听队列
              //声明队列

              /**
               *参数
               * 1、string queue
               * 2、boolean autoAck
               * 3、Consumer callback
               */
               channel.basicConsume(QUEUE_INFORM_EMAIL, true, defaultConsumer);
       }
   }

测试:
打开RabbitMQ的管理界面,观察交换机绑定情况:
当生产者服务启动后可以看到交换机里面绑定了两个队列
在这里插入图片描述
而队列里面可以看到待发送10条 总共10条
在这里插入图片描述
当把两个消费者服务起来后可以看到连接里面有两个通道
在这里插入图片描述
而每个通道可以看到生产者和消费者具体信息
在这里插入图片描述
在这里插入图片描述
工作队列模式和发布订阅模式的区别
1)work queues不用定义交换机,而publish/subscribe需要定义交换机
2)publish/subscribe的生产方是面向交换机发送消息,work queues的生产方是面向队列发送消息(底层使用默认 交换机)。
3)publish/subscribe需要设置队列和交换机的绑定,work queues不需要设置,实质上work queues会将队列绑 定到默认的交换机 。

相同点: 两者实现的发布/接收的效果是一样的,多个消费端监听同一个队列不会重复消费消息。

在这里插入图片描述
c1相当于短信消费者 c2,c3相当于email消费者 当短信消费者启动一个服务 而email启动多个服务时 可以看到队列没有变化 而监听的成员是三个
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值