6.rabbitmq中exchange的几种形式

rabbitmq中exchange的几种形式

RabbitMQ 消息传递模型的核心思想是: 生产者生产的消息从不会直接发送到队列。实际上,通常生产 者甚至都不知道这些消息传递传递到了哪些队列中。

相反,生产者只能将消息发送到交换机**(exchange)**,交换机工作的内容非常简单,一方面它接收来 自生产者的消息,另一方面将它们推入队列。交换机必须确切知道如何处理收到的消息。是应该把这些消 息放到特定队列还是说把他们到许多队列中还是说应该丢弃它们。这就的由交换机的类型来决定。

交换机一共有以下几种类型

  • direct:直接
  • topic:主题
  • headers:标题
  • fanout:扇出

什么是 bingding 呢,binding 其实是 exchange 和 queue 之间的桥梁,它告诉我们 exchange 和那个队 列进行了绑定关系。

临时队列

通过使用以下方式来创建一个临时队列,命名随机,一旦我们断开了消费者的连接,队列将被自动删除。

String queue = channel.queueDeclare().getQueue();

在这里插入图片描述

Fanout类型

Fanout 这种类型非常简单。正如从名称中猜到的那样,它是将接收到的所有消息广播到它知道的所有队列中。

案例:构建一个简单的日志系统,生产者将发出日志消息,我们启动两个消费者,第一个消费者将日志持久化到磁盘中,第二个消费者会在控制台打印在屏幕上。即生产者将消息广播给所有消费者

6.rabbitmq中exchange的几种形式_第1张图片

生产者演示
/**
 *  fanout 类型 生产者
 */
public class FanoutProducer {

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitUtil.getChannel();
        /**
         * 声明一个exchange
         *      String exchange:exchange的名称
         *      String type:exchange的类型
         */
        channel.exchangeDeclare(ExchangeNames.LOGS,"fanout");
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()){
            String message = scanner.nextLine();
						channel.basicPublish(ExchangeNames.LOGS,"",null,message.getBytes(StandardCharsets.UTF_8));
            System.out.println("生产者发出消息"+ message);
        }
    }
}
消费者1(写入磁盘)
/**
 * fanout 类型 消费者1
 */
public class FanoutCustomer1 {

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitUtil.getChannel();
        channel.exchangeDeclare(ExchangeNames.LOGS,"fanout");
        String queue = channel.queueDeclare().getQueue();
        channel.queueBind(queue,ExchangeNames.LOGS,"");
        System.out.println("fanoutCustomer1 等待接收消息,把消息写到磁盘中");
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            String receive = new String(message.getBody());
            System.out.println("接收到数据成功:"+receive+",写入磁盘中");
        };
        channel.basicConsume(queue,true,deliverCallback,consumerTag -> {});
    }
}
消费者2(输出在控制台)
/**
 * fanout 类型消费者2
 */
public class FanoutCustomer2 {

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitUtil.getChannel();
        channel.exchangeDeclare(ExchangeNames.LOGS,"fanout");
        String queue = channel.queueDeclare().getQueue();
        channel.queueBind(queue,ExchangeNames.LOGS,"");
        System.out.println("fanoutCustomer2 等待接收消息,把消息打印在控制台");
        DeliverCallback deliverCallback = (consumerTag, message) -> {
            String receive = new String(message.getBody());
            System.out.println("接收到数据成功:"+receive+",打印到控制台。。。");
        };
        channel.basicConsume(queue,true,deliverCallback,consumerTag -> {});
    }
}

Exchange和queue的绑定关系如下图所示

6.rabbitmq中exchange的几种形式_第2张图片

Direct类型

fanout类型的并不能给我们带来很大的灵活性,它只能进行无意义的广播,而direct类型可以在队列和exchange的bingding中指定一个routingKey,消息只去到它绑定的routingKey中去。

6.rabbitmq中exchange的几种形式_第3张图片

  • 如图所示,exchange绑定了两个队列,绑定类型事direct,队列console的绑定键为warninginfo,而disk的绑定键为error
  • 在这种情况下,生产者发布消息到exchange上,绑定为warninginfo的会发布到队列console上,绑定为error的会发布到队列disk上,其他消息会被丢弃。

6.rabbitmq中exchange的几种形式_第4张图片

  • 如果exchange的绑定类型是direct,但是它绑定的多个队列的key都相同,在这种情况下虽然绑定类型事direct,但是它表现的就和fanout有点类似了,就跟广播差不多。
生产者
/**
 * direct 类型 生产者
 */
public class DirectProducer {

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitUtil.getChannel();
        //声明exchange类型
        channel.exchangeDeclare(ExchangeNames.DIRECT_LOG,"direct");
        //声明binding关系
        Map<String,String> bindingKeys = new HashMap<>();
        bindingKeys.put("info","普通info信息");
        bindingKeys.put("error","错误error信息");
        bindingKeys.put("warning","警告warning信息");
        bindingKeys.put("debug","调试debug信息");
        //发送消息
        for (Map.Entry<String, String> entry : bindingKeys.entrySet()) {
            String key = entry.getKey();
            String message = entry.getValue();    						   		  channel.basicPublish(ExchangeNames.DIRECT_LOG,key,null,message.getBytes(StandardCharsets.UTF_8));
            System.out.println("生产者发出消息:消息类型为--"+key+",内容为:"+message);
        }
    }
}
消费者1
/**
 * direct 类型 消费者1
 */
public class DirectCustomer1 {

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitUtil.getChannel();
        channel.exchangeDeclare(ExchangeNames.DIRECT_LOG, BuiltinExchangeType.DIRECT);

        String queueName = "console";
        channel.queueDeclare(queueName,false,false,false,null);
        channel.queueBind(queueName,ExchangeNames.DIRECT_LOG,"info");
        channel.queueBind(queueName,ExchangeNames.DIRECT_LOG,"warning");
        System.out.println("DirectCustomer1 等待接收消息,接收info和warning 的消息类型");

        DeliverCallback deliverCallback = (consumerTag, message) -> {
            String receive = new String(message.getBody());
            System.out.println("接收绑定键:"+message.getEnvelope().getRoutingKey()+",消息 :"+receive);
        };
        channel.basicConsume(queueName,true,deliverCallback,consumerTag -> {});
    }
}
消费者2
/**
 * direct 类型 消费者2
 */
public class DirectCustomer2 {

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitUtil.getChannel();
        channel.exchangeDeclare(ExchangeNames.DIRECT_LOG, BuiltinExchangeType.DIRECT);

        String queueName = "disk";
        channel.queueDeclare(queueName,false,false,false,null);
        channel.queueBind(queueName,ExchangeNames.DIRECT_LOG,"error");
        System.out.println("DirectCustomer2 等待接收消息,接收error 的消息类型");

        DeliverCallback deliverCallback = (consumerTag, message) -> {
            String receive = new String(message.getBody());
            System.out.println("接收绑定键:"+message.getEnvelope().getRoutingKey()+",消息 :"+receive+",保存到磁盘");
        };
        channel.basicConsume(queueName,true,deliverCallback,consumerTag -> {});
    }
}

direct类型的binging关系

6.rabbitmq中exchange的几种形式_第5张图片

topic类型

尽管使用 direct 交换机改进了我们的系统,但是它仍然存在局限性-比方说我们想接收的日志类型有 info.baseinfo.advantage,某个队列只想 info.base 的消息,那这个时候 direct 就办不到了。这个时候就只能使用 topic 类型。

发送到类型是 topic 交换机的消息的 routing_key 不能随意写,必须满足一定的要求,它必须是一个单词列表,以点号分隔开。这些单词可以是任意单词,比如说:stock.usd.nyse, nyse.vmw, quick.orange.rabbit这种类型的。当然这个单词列表最多不能超过 255 个字节

在这些规则列表中

  • *可以代替一个单词
  • #可以代替零个或多个单词
  • 当一个队列绑定键是#,那么这个队列将接收所有数据,就有点像fanout
  • 如果队列绑定键中没有#*出现,那么该队列绑定类型就是direct

6.rabbitmq中exchange的几种形式_第6张图片

生产者
/**
 * topic 类型 生产者
 */
public class TopicProducer {

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitUtil.getChannel();
        //声明exchange类型
        channel.exchangeDeclare(ExchangeNames.TOPIC_LOG, BuiltinExchangeType.TOPIC);
        //声明binding关系
        Map<String,String> bindingKeys = new HashMap<>();
        bindingKeys.put("error.bus.core","被Q1和Q2收到");
        bindingKeys.put("error.common.print","被Q1和Q2收到");
        bindingKeys.put("common.base.core","被Q1收到");
        bindingKeys.put("error.bus","被Q2收到");
        bindingKeys.put("file.common.upload","被Q1收到");
        //发送消息
        for (Map.Entry<String, String> entry : bindingKeys.entrySet()) {
            String key = entry.getKey();
            String message = entry.getValue();
            channel.basicPublish(ExchangeNames.TOPIC_LOG,key,null,message.getBytes(StandardCharsets.UTF_8));
            System.out.println("生产者发出消息:消息类型为--"+key+",内容为:"+message);
        }
    }
}
消费者1
/**
 * topic 类型 消费者1
 */
public class TopicCustomer1 {

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitUtil.getChannel();
        channel.exchangeDeclare(ExchangeNames.TOPIC_LOG, BuiltinExchangeType.TOPIC);

        String queueName = "Q1";
        channel.queueDeclare(queueName,false,false,false,null);
        channel.queueBind(queueName,ExchangeNames.TOPIC_LOG,"*.*.core");
        channel.queueBind(queueName,ExchangeNames.TOPIC_LOG,"*.common.*");
        System.out.println("TopicCustomer1 等待接收消息,接收*.*.core和*.common.* 的消息类型");

        DeliverCallback deliverCallback = (consumerTag, message) -> {
            String receive = new String(message.getBody());
            System.out.println("接收绑定键:"+message.getEnvelope().getRoutingKey()+",消息 :"+receive);
        };
        channel.basicConsume(queueName,true,deliverCallback,consumerTag -> {});
    }
}

消费者2
/**
 * topic 类型 消费者2
 */
public class TopicCustomer2 {

    public static void main(String[] args) throws IOException {
        Channel channel = RabbitUtil.getChannel();
        channel.exchangeDeclare(ExchangeNames.TOPIC_LOG, BuiltinExchangeType.TOPIC);

        String queueName = "Q2";
        channel.queueDeclare(queueName,false,false,false,null);
        channel.queueBind(queueName,ExchangeNames.TOPIC_LOG,"error.#");
        System.out.println("TopicCustomer1 等待接收消息,接收error.#的消息类型");

        DeliverCallback deliverCallback = (consumerTag, message) -> {
            String receive = new String(message.getBody());
            System.out.println("接收绑定键:"+message.getEnvelope().getRoutingKey()+",消息 :"+receive);
        };
        channel.basicConsume(queueName,true,deliverCallback,consumerTag -> {});
    }
}

topic中的binding关系

6.rabbitmq中exchange的几种形式_第7张图片

你可能感兴趣的:(rabbitmq,java-rabbitmq,rabbitmq,java)