RabbitMQ工作模式——Publish/Subscribe模式(订阅模式)

大伙可以到我的RabbitMQ专栏获取更多信息

模式说明

RabbitMQ工作模式——Publish/Subscribe模式(订阅模式)_第1张图片

Publish/Subscribe模式,也叫订阅模式,在该模式中,使用到了Exchanger(交换机),消息的传递过程发生了变化:

  • Publisher(生产者):消息现在不直接发送到Queue中了,而是把消息发送给Exchanger
  • Consumer(消费者):消息的接收者,会一直等待消息的到来
  • Queue(队列):消息队列接收消息并缓存消息
  • Exchanger(交换机):
    • 接收生产者发送的消息
    • 处理消息的分发,如将消息传递给某一个特定的队列、传递给多有队列、将消息丢弃等,至于如何来决定消息的去向取决于消息的类型:
      • Fanout:方波,将消息交给所有绑定到该Exchanger的队列
      • Direct:定向,将消息传递给符合执行routing key的队列
      • Topic:通配符,把消息传递给符合routing pattern(路由模式)的队列
      • Headers:不处理路由键。而是根据发送的消息内容中的headers属性进行匹配。在绑定Queue与Exchange时指定一组键值对;当消息发送到RabbitMQ时会取到该消息的headers与Exchange绑定时指定的键值对进行匹配;如果完全匹配则消息会路由到该队列,否则不会路由到该队列。headers属性是一个键值对,可以是Hashtable,键值对的值可以是任何类型,而fanout,direct,topic 的路由键都需要要字符串形式的
    • Exchanger只负责消息的转发,没有消息的存储能力,所以如果没有任何队列和Exchanger绑定,或者没有找到该message符合要求的队列,那么消息将会被丢弃

由上述特点可知订阅模式其实就是通过Exchanger对消息的去向进行规划的模式

生产者

与之前简单模式和Work queues模式不一样的是:

  • 创建了交换机
  • 创建了两个队列并绑定在交换机上
  • 消息的push对象由队列变为了交换机
package com.leolee.rabbitmq;

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 ProducerPubSub
 * @Description: Publish/Subscribe模式
 * @Author LeoLee
 * @Date 2020/11/6
 * @Version V1.0
 **/
public class ProducerPubSub {

    public static void main(String[] args) throws IOException, TimeoutException {

        //1.创建连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //2.设置参数
        connectionFactory.setHost("127.0.0.1");//默认值为localhost
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/LeoLee");//默认值为:/
        connectionFactory.setUsername("LeoLee");
        connectionFactory.setPassword("lyl512240816");

        //3.创建连接 connection
        Connection connection = connectionFactory.newConnection();

        //4.创建channel
        Channel channel = connection.createChannel();

        //5.创建交换机
        /*
        String exchange:交换机名称
        BuiltinExchangeType type:交换机类型,枚举,
        boolean durable:是否持久化
        boolean autoDelete:是否自动删除,当没有消费者的时候自动删除
        boolean internal:是否内部使用,一般都是false,true代表给MQ内部使用的,比如给MQ开发的插件使用
        Map arguments:相关参数
         */
        String exchangerName = "test_fanout";
        channel.exchangeDeclare(exchangerName, BuiltinExchangeType.FANOUT, false, false, false, null);

        //6.创建队列
        /*
         String queue:队列名称
         boolean durable:是否持久化
         boolean exclusive: 有如下两个意义
            是否独占,只有一个消费者监听这个队列
            当connection关闭时,是否删除队列
         boolean autoDelete:是否自动删除,当没有消费者的时候自动删除
         Map arguments: 一些配置参数
         */
        //如果没有一个名字叫xxx的队列,则会创建,如果存在该队列,则复用
        String queueName1 = "test_fanout_queue1";
        String queueName2 = "test_fanout_queue2";
        channel.queueDeclare(queueName1, false, false, false, null);
        channel.queueDeclare(queueName2, false, false, false, null);

        //7.绑定队列和交换机
        /*
        String queue:队列名称
        String exchange:交换机名称
        String routingkey:路由键,绑定规则
            如果交换机的类型为 fanout,routingkey设置为空值""
        */
        channel.queueBind(queueName1, exchangerName, "");
        channel.queueBind(queueName2, exchangerName, "");

        //8.发送消息
        String body = "日志信息:又是不想当社畜的一天";
        channel.basicPublish(exchangerName, "", null, body.getBytes());//第二个参数routingkey为空

        //9.释放资源
        channel.close();
        connection.close();

    }

}

运行生产者代码:

交换机已创建

RabbitMQ工作模式——Publish/Subscribe模式(订阅模式)_第2张图片

两个队列已创建并各自拥有一条消息,说明生产者发送的一条消息被两个队列都获取到了

消费者

运行两个消费者分别从这两个队列获取message,代码如下:

package com.leolee.rabbitmq;

import com.rabbitmq.client.*;

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

/**
 * @ClassName ConsumerPubSub1
 * @Description: Publish/Subscribe模式
 * @Author LeoLee
 * @Date 2020/11/6
 * @Version V1.0
 **/
public class ConsumerPubSub1 {

    public static void main(String[] args) throws IOException, TimeoutException {

        //1.创建连接工厂
        ConnectionFactory connectionFactory = new ConnectionFactory();

        //2.设置参数
        connectionFactory.setHost("127.0.0.1");//默认值为localhost
        connectionFactory.setPort(5672);
        connectionFactory.setVirtualHost("/LeoLee");//默认值为:/
        connectionFactory.setUsername("LeoLee");
        connectionFactory.setPassword("lyl512240816");

        //3.创建连接 connection
        Connection connection = connectionFactory.newConnection();

        //4.创建channel
        Channel channel = connection.createChannel();

        //5.创建队列queue(由于简单模式不需要Exchange,其实是使用默认的交换机,所以消息直接入队列),消费者可以不需要创建队列,但是创建了也不影响
        /*
         String queue:队列名称
         boolean durable:是否持久化
         boolean exclusive: 有如下两个意义
            是否独占,只有一个消费者监听这个队列
            当connection关闭时,是否删除队列
         boolean autoDelete:是否自动删除,当没有消费者的时候自动删除
         Map arguments: 一些配置参数
         */
        //如果没有一个名字叫Hello_world的队列,则会创建,如果存在该队列,则复用
        //生产者已经生命过了队列,可以忽略该步骤
        //channel.queueDeclare("workQueues", false, false, false, null);
        String queueName1 = "test_fanout_queue1";

        //6.接收消息
        /*
         * String queue:队列名称
         * boolean autoAck:是否自动确认,当消费者收到消息之后会自动给MQ一个回执,告诉MQ消息已经收到
         * Consumer callback:回调方法
         */
        Consumer consumer = new DefaultConsumer(channel){

            /*
             * 功能描述: 
* 〈回调方法〉当客户端收到消息并向MQ确认消息已经收到,将回调该方法 * @Param: [consumerTag消息唯一标识, * envelope获取一些信息,包含交换机信息、routing key...等, * properties配置信息,生产者发送消息时候的配置, * body数据] * @Return: void * @Author: LeoLee * @Date: 2020/11/5 11:56 */ @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { /*System.out.println("consumerTag:" + consumerTag); System.out.println("envelope.exchange:" + envelope.getExchange()); System.out.println("envelope.routingKey:" + envelope.getRoutingKey()); System.out.println("properties:" + properties);*/ System.out.println("消费者1从队列" + queueName1 + "接收到body:" + new String(body)); } }; channel.basicConsume(queueName1, true, consumer); //7.消费者不需要关闭资源,不然无法完成自动确认 } }

RabbitMQ工作模式——Publish/Subscribe模式(订阅模式)_第3张图片

RabbitMQ工作模式——Publish/Subscribe模式(订阅模式)_第4张图片

此时消费者从各自对应的通道内消费了来自于生产者发送的同一条message,和就是订阅模式,其实可以理解为广播,这边吆喝一嗓子,所有人都能听得到。

 

你可能感兴趣的:(#,RabbitMQ,rabbitmq,pub/sub,java,交换机,订阅)