交换器类型

      RabbitMQ常用的交换器类型有fanout、direct、topic、headers这四种。AMOP协议里还提到另外两种类型:System和自定义。本文着重介绍常用的四种类型。
本系列完整代码见GitHub

direct

      direct类型的交换器路由规则十分简单,它会把消息路由到那些BindingKey和RoutingKey完全匹配的队列中。
请输入图片描述

      以图一为例,交换器类型为direct,如果我们发送一条消息,并在发送消息的时候设置路由键为"waring",则消息会路由到Queue1和Queue2。

//Producer
String exchangeName = "direct_exchange";
String routingKey = "waring";
String msg = "waring message";
channel.basicPublish(exchangeName,routingKey,null,msg.getBytes());

//Consumer
String exchangeName = "direct_exchange";
String exchangeType = "direct";
String queueName = "test_queue";
String routingKey = "waring";
//声明交换器
channel.exchangeDeclare(exchangeName,exchangeType,true,false,false,null);
channel.queueDeclare(queueName,false,false,false,null);
//将交换器和队列绑定
channel.queueBind(queueName,exchangeName,routingKey);

      经过测试我们会发现direct类型的交换器需要保证生产者和消费者的routingkey完全一致,与队列名无关。

topic

      direct类型的交换器路由规则是完全匹配BindingKey和RoutingKey,但是这种严格的匹配方式在很多情况下不能满足实际业务的需求。topic类型的交换器在匹配规则上进行了扩展,它与direct类型的交换器相似,也是将消息路由到BindingKey和RoutingKey相匹配的队列中,但这里的匹配规则有些不同,它约定:

  • RoutingKey为一个点号"."分隔的字符串(被点号"."分隔开的每一段独立的字符串称为一个单词),如“com.rabbitmq.client”、“java.util.concurrent”、“com.hidden.client”;
  • BindingKey和RoutingKey一样也是点号"."分隔的字符串;
  • BindingKey中可以存在两种特殊字符串"*"和"#",用于做模糊匹配,其中"*"用于匹配一个单词,"#"用于匹配多规格单词(可以是零个)。(注意此处"*"与正则中的不同)
    请输入图片描述
//Producer
String exchangeName = "topic_exchange";
//四种routing key
String routingKey1 = "waring.user";
String routingKey2 = "info.news";
String routingKey3 = "info.me";
String routingKey4 = "waring.work";
String routingKey5 = "warn.user2";

channel.basicPublish(exchangeName,routingKey1,null,"waring from user module".getBytes());
channel.basicPublish(exchangeName,routingKey2,null,"info from news module".getBytes());
channel.basicPublish(exchangeName,routingKey3,null,"info from me module".getBytes());
channel.basicPublish(exchangeName,routingKey4,null,"waring from work module".getBytes());
channel.basicPublish(exchangeName,routingKey5,null,"waring from user2 module".getBytes());

//Consumer
String exchangeName = "topic_exchange";
String exchangeType = "topic";
String queueName = "testqueue";
String routingKey = "waring.#";//接收waring.user和waring.work的消息
//声明交换器
channel.exchangeDeclare(exchangeName,exchangeType,true,false,false,null);
channel.queueDeclare(queueName,false,false,false,null);
//将交换器和队列绑定
channel.queueBind(queueName,exchangeName,routingKey);

fanout

      它会把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中。和routing key无关。

//Producer
String exchangeName = "fanout_exchange";
String routingKey = "waring.user";//可以不设置,设置了也无所谓
channel.basicPublish(exchangeName,routingKey,null,"waring message".getBytes());

//Consumer
String exchangeName = "fanout_exchange";
String exchangeType = "fanout";
String queueName = "fanout_queue";
String routingKey = "";//不设置routing key
//声明交换器
channel.exchangeDeclare(exchangeName,exchangeType,true,false,false,null);
channel.queueDeclare(queueName,false,false,false,null);
//将交换器和队列绑定
channel.queueBind(queueName,exchangeName,routingKey);

headers

      headers类型的交换器不依赖于路由键的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。在绑定队列和交换器时制定一组键值对,当发送消息到交换器时,RabbitMQ会获取到该消息的headers(也是一个键值对的形式),对比其中的键值对是否完全匹配队列和交换器绑定时指定的键值对,如果完全匹配则消息会路由到该队列,否则不会路由到该队列。headers类型的交换器性能会很差,而且也不实用,基本上不会看到它的存在。

//Producer
String exchangeName = "headers_exchange";
String routingKey = "waring.user";//和routing key无关
Map<String,Object> headers = new HashMap<>();
headers.put("source","usermodule");
AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
        .headers(headers)
        .build();
channel.basicPublish(exchangeName,routingKey,properties,"waring message".getBytes());

//Consumer
String exchangeName = "headers_exchange";
String exchangeType = "headers";
String queueName = "headers_queue";
String routingKey = "headers.routingkey";//和routing key无关
//声明交换器
channel.exchangeDeclare(exchangeName,exchangeType,true,false,false,null);
channel.queueDeclare(queueName,false,false,false,null);
Map<String, Object> headers = new HashMap<>();
headers.put("source","usermodule");
//将交换器和队列绑定,设置headers
channel.queueBind(queueName,exchangeName,routingKey,headers);
Last modification:May 20th, 2020 at 02:10 pm
如果觉得我的文章对你有用,请随意赞赏