【RabbitMQ】三种类型交换器 Fanout,Direct,Topic

本文介绍了RabbitMQ中三种交换器类型:Fanout、Direct和Topic的工作原理及应用场景。Fanout交换器将消息广播到所有绑定队列;Direct交换器依据精确匹配路由键转发消息;Topic交换器支持模式匹配,利用通配符实现灵活的消息路由。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  RabbitMQ服务器会根据路由键将消息从交换器路由到队列中,如何处理投递到多个队列的情况?这里不同类型的交换器起到了重要的作用。分别是fanout,direct,topic,每一种类型实现了不同的路由算法。

 

Fanout Exchange 

  不处理路由键。你只需要简单的将队列绑定到交换机上。一个发送到交换机的消息都会被转发到与该交换机绑定的所有队列上。很像子网广播,每台子网内的主机都获得了一份复制的消息。Fanout交换机转发消息是最快的。 


      

生产者

package com.dynamic.rabbitmy.ps;

/**
 * Created by fxq on 2017/3/10.
 */

import com.dynamic.rabbitmy.util.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

/**
 * 生产者
 */
public class Send {
    private final static  String  EXCHANGE_NAME="test_exchange_fanout";
    public static void main(String[] args) throws  Exception{
        //获取到连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明交换器
        channel.exchangeDeclare(EXCHANGE_NAME,"fanout");//fanout交换器
        //消息内容
        String message = "商品已经删除,id=1000";
        channel.basicPublish(EXCHANGE_NAME,"",null,message.getBytes());
        System.out.println(" [x] Sent'"+message+"'" );
        channel.close();
        connection.close();
    }
}

消费者

package com.dynamic.rabbitmy.ps;
/**
 * Created by fxq on 2017/3/10.
 */
import com.dynamic.rabbitmy.util.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;
/**
 * 消费者
 */
public class Recv
{
    private final static String QUEUE_NAME="test_queue_fanout_1";
    private final static String EXCHANGE_NAME="test_exchange_fanout";
    public static void main(String[] args) throws Exception{
        //获取到连接以及通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列到交换器
        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,""); //不设置路由键
        //统一时刻服务器只会发一条消息给消费者;
        channel.basicQos(1);
        //定义队列的消费者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //监听队列,手动返回完成
        channel.basicConsume(QUEUE_NAME,false,consumer);
        //获取消息
        while (true)
        {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println(" 前台系统:'" + message + "'");
            Thread.sleep(10);
            //手动返回
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
        }
    }
}


Direct Exchange 

  处理路由键。需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配。这是一个完整的匹配。如果一个队列绑定到该交换机上要求路由键 “test”,则只有被标记为“test”的消息才被转发,不会转发test.aaa,也不会转发dog.123,只会转发test。 

     


生产者:

package com.dynamic.rabbitmy.routing;

/**
 * Created by fxq on 2017/3/10.
 */

import com.dynamic.rabbitmy.util.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;

/**
 * 生产者
 */
public class Send {
    private final static String EXCHANGE_NAME="test_exchange_direct";
    public static void main(String[] args)  throws Exception{
        //获取到连接以及通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明exchange
        channel.exchangeDeclare(EXCHANGE_NAME,"direct");
        //消息内容
        String message = "删除商品,id = 1001";
        channel.basicPublish(EXCHANGE_NAME,"delete",null,message.getBytes()); //此处delete为路由键;
        System.out.println(" [x] Sent '"+ message+"'");
        channel.close();
        connection.close();
    }
}


生产者:

package com.dynamic.rabbitmy.routing;

/**
 * Created by fxq on 2017/3/10.
 */

import com.dynamic.rabbitmy.util.ConnectionUtil;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;

/**
 * 消费者1
 */
public class Recv {

    private final static String QUEUE_NAME="test_queue_direct_1";
    private final static String EXCHANGE_NAME="test_exchange_direct";
    public static void main(String[] args) throws Exception{
        //获取连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明队列
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定队列到交换机;
        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"update");  //匹配路由键为update
        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"delete");  //匹配路由键是delete
        //同一时刻服务器只会发送一条消息给消费者;
        channel.basicQos(1);
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //监听队列,手动返回完成
        channel.basicConsume(QUEUE_NAME,false,consumer);
        //获取消息
        while (true)
        {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("前台系统:'"+message+"'");
            Thread.sleep(10);
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
        }
    }
}

  该绑定在交换器上的队列,它可以匹配delete,update的路由键,但不是能匹配insert;必须和生产者声明是一模一样;


Topic Exchange 

  将路由键和某模式进行匹配。此时队列需要绑定要一个模式上。符号“#”匹配一个或多个词,符号“*”匹配不多不少一个词。因此“audit.#”能够匹配到“audit.irs.corporate”,但是“audit.*” 只会匹配到“audit.irs”。


    

生产者:

package com.dynamic.rabbitmy.topic;

/**
 * Created by fxq on 2017/3/10.
 */

import com.dynamic.rabbitmy.util.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
/**
 * 发送者
 */
public class Send {
    private final  static String EXCHANGE_NAME="test_exchange_topic" ;
    public static void main(String[] args) throws  Exception{
        //获取到连接以及mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明exchange
        channel.exchangeDeclare(EXCHANGE_NAME,"topic");
        //消息内容
        String message = "插入商品,id=100";
        //发布消息
        channel.basicPublish(EXCHANGE_NAME,"item.insert",null,message.getBytes());
        System.out.println(" [x] Sent '"+message + "'");
        channel.close();
        connection.close();
    }
}

消费者:

package com.dynamic.rabbitmy.topic;

import com.dynamic.rabbitmy.util.ConnectionUtil;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.QueueingConsumer;
import com.sun.media.sound.SF2InstrumentRegion;

/**
 * Created by fxq on 2017/3/10.
 */
public class Recv2 {

    private final  static  String QUEUE_NAME="test_queue_topic2";
    private final  static String EXCHANGE_NAME="test_exchange_topic" ;
    public static void main(String[] args) throws  Exception{
        //获得连接和mq通道
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        //声明通道
        channel.queueDeclare(QUEUE_NAME,false,false,false,null);
        //绑定exchange
        channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"item.#");   //使用item.# 匹配所有的以item开头的
        //同一时刻服务器只能发送一条消息给消费者;
        channel.basicQos(1);
        //声明消费者
        QueueingConsumer consumer = new QueueingConsumer(channel);
        //监控队列,设置手动完成
        channel.basicConsume(QUEUE_NAME,false,consumer);
        while (true)
        {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());
            System.out.println("搜索系统 '" + message + "'");
            Thread.sleep(10);
            channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
        }
    }
}


  以上就是三种交换器的类型以及他们的使用场景,基于消息的路由键和交换器的类型,服务器会决定将消息投递到那个队列中。


<think>嗯,用户问的是RabbitMQ的四种交换器类型有什么区别。我需要先回忆一下这四种交换器的名称和各自的特点。RabbitMQ常用的交换器类型DirectFanoutTopic和Headers。每种类型在路由消息时有不同的机制,所以它们的应用场景也不同。 首先,Direct交换器是根据消息的路由键(Routing Key)和绑定键(Binding Key)完全匹配来路由消息的。比如,如果一个队列绑定到Direct交换器时指定了Binding Key为“error”,那么只有路由键为“error”的消息才会被发送到这个队列。这种类型适用于精确匹配的场景,比如日志处理中的不同级别日志分发。 然后是Fanout交换器,它会把消息广播到所有绑定的队列,完全忽略路由键。这种类型适合需要将消息分发给多个消费者的场景,比如发布/订阅模式,一个消息需要被多个系统处理的时候。 接下来是Topic交换器,它允许使用通配符来匹配路由键和绑定键。绑定键可以包含“*”和“#”通配符,其中“*”匹配一个单词,“#”匹配零个或多个单词。这种类型适合需要根据模式匹配进行路由的情况,比如根据消息的多个属性组合来分发消息。 最后是Headers交换器,它不依赖于路由键,而是根据消息的头部属性(Headers)进行匹配。绑定队列时可以指定多个头部属性的匹配条件,如x-match参数设置为all或any来决定是全部匹配还是任一匹配。这种类型适用于需要复杂条件判断的场景,但使用较少,因为Headers可能不如路由键高效。 要确认这些信息是否正确,比如Headers交换器是否真的不常用,或者Topic交换器的通配符规则有没有记错。另外,可能用户在使用这些交换器时需要注意它们的性能差异,比如Fanout由于广播可能会更消耗资源,而Direct则更高效。 最后,用户可能需要了解如何在实际代码中声明这些交换器,以及如何绑定队列。可能需要给出Java中使用RabbitMQ客户端的示例代码,比如使用channel.exchangeDeclare方法,并指定不同的类型。例如,创建Direct交换器的代码示例,以及绑定队列时的参数设置。 总结一下,四种交换器的区别主要在于路由机制和适用场景。用户可能需要进一步了解如何选择适合自己业务需求的交换器类型,或者如何在代码中正确配置它们。另外,可能的问题可能涉及交换器的性能、使用时的注意事项,或者与其他消息队列概念的对比。</think><< RabbitMQ的四种交换器类型及其区别如下: 1. **Direct Exchange(直连交换器)** - **路由机制**:完全匹配RoutingKey和BindingKey - **适用场景**:点对点精确路由(如日志级别过滤) ```java channel.exchangeDeclare("directExchange", BuiltinExchangeType.DIRECT); channel.queueBind(queueName, "directExchange", "error"); ``` 2. **Fanout Exchange(扇出交换器)** - **路由机制**:忽略RoutingKey,广播到所有绑定队列 - **适用场景**:发布/订阅模式(如新闻推送) ```java channel.exchangeDeclare("fanoutExchange", BuiltinExchangeType.FANOUT); channel.queueBind(queueName, "fanoutExchange", ""); // 无需指定RoutingKey ``` 3. **Topic Exchange(主题交换器)** - **路由机制**:使用通配符匹配(*匹配单个单词,#匹配多级路径) - **适用场景**:多维度消息分类(如传感器数据路由) ```java channel.exchangeDeclare("topicExchange", BuiltinExchangeType.TOPIC); channel.queueBind(queueName, "topicExchange", "sensor.temperature.*"); ``` 4. **Headers Exchange(头交换器)** - **路由机制**:基于消息头键值对匹配(x-match参数控制all/any逻辑) - **适用场景**:复杂属性路由(如同时满足多个条件) ```java Map<String, Object> headers = new HashMap<>(); headers.put("format", "csv"); headers.put("priority", 1); headers.put("x-match", "all"); // 需要同时满足 channel.exchangeDeclare("headersExchange", BuiltinExchangeType.HEADERS); channel.queueBind(queueName, "headersExchange", "", headers); ``` **核心区别对比表**: | 类型 | 路由依据 | 匹配方式 | 性能 | 使用频率 | |-----------|------------|------------|------|------| | Direct | RoutingKey | 精确匹配 | 最高 | 高 | | Fanout | 无 | 广播所有队列 | 低 | 中 | | Topic | RoutingKey | 通配符模式匹配 | 中 | 高 | | Headers | 消息头属性 | 键值对条件匹配 | 最低 | 低 |
评论 28
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值