一.交换机 1.Exchange
在RabbitMQ中,生产者发送消息不会直接将消息投递到队列中,而是先将消息投递到交换机中,在由交换机转发到具体的队列,队列再将消息以推送或者拉取方式给消费者进行消费
生产者将消息发送到Exchange,由Exchange再路由到一个或多个队列中
2.路由键( Routingkey)
生产者将消息发送给交换机的时候,会指定RoutingKey指定路由规则。
3.绑定键(Bindi ngKey)
通过绑定键将交换机与队列关联起来,这样RabbitMQ就知道如何正确地将消息路由到队列。
4.小结
生产者将消息发送给哪个Exchange是需要由RoutingKey决定的,生产者需要将Exchange与哪个队列绑定时需要由BindingKey决定的。
二.交换机类型 1.直连交换机: Direct exchange
直连交换机的路由算法非常简单:将消息推送到binding key与该消息的routing key相同的队列.
直连交换机X上绑定了两个队列。第一个队列绑定了绑定键orange,第二个队列有两个绑定键:black和green
在这种场景下,一个消息在布时指定了路由键为orange将会只被路由到队列Q1,路由键为black和green的消息都将被路由到队列Q2。其他的消息都将被丢失
同一个绑定键可以绑定到不同的队列上去,可以增加一个交换机X与队列Q2的绑定键,在这种情况下,直连交换机将会和广播交换机有着相同的行为,将消息推送到所有匹配的队列。一个路由键为black的消息将会同时被推送到队列Q1和Q2.
2.主题交换机: Topic exchange
直连交换机的缺点:
直连交换机 grouting key 方案非常简单,如果我们希望一条消息发送给多个队列,那么这个交换机需要绑定上非常多的 routing key .假设每个交换机上都绑定一维的 routing key 连搜到各个队列上、那么消息的管理求会异常地困难。
主题交换机的特点:
发送到主题交换机的消息不能有任意的 routing key ,必须是由点号分开的一串单词,这些单词可以是任意的,但通常是与消息相关的一些特征
比如以下是几个有效的: routing key :" stock 、usd 、nyse "," nyse 、vmw ”," quick 、orange 、rabblt ”, routing key 的单词可以有很多,最大限制是255 bytes .
Topic 交换机的逻辑与 direct 交换机有点相似使用特定路由键发送的消息将被发送到所有使用匹配绑定键绑定的队列,然而,绑定键有两个特殊的情况:
①表示匹配任意一个单词
②表示匹配任意一个或多个单词
延申
当一个队列的绑定健是°#,它将会接收所有的消息,而不再考慮所接收消息的路由键
当一个队列的绑定键没有用到#和*时,它又像 direct 交换一样工作。
3.扇形交换机: Fanout exchange
扇形交换机是最基本的交换机类型,它所能做的事悄非常简单广播消息。
扇形交换机会把能接收到的消息全部发送给绑定在自己身上的队列。因为广播不需要思考”,所以扇形交换机处理消息的速度也是所有的交换机类型里面最快的。
首部交换机和扇形交换机都不界要路由键 routingKey 交换机时通过 Headers 头部来将消息映射到队列的,有点像 HTTP 的 Headers .
Hash 结构中要求携带一个健×- match ”,这个键的 Value 可以是 any 或者 al ,这代表消息携带的 Hash 是需要全部匹 al ),还是仅四配一个健( any )就可以了。
相比直连交换机,首部交换机的优勢是匹配配的规则不被限定为字符串( string )而是 Object 类型。
5.默认交换机all :在发布消息时携带的所有 Entry 必须和绑定在队列上的所有 Entry 完全匹配
any :只要在发布消息时携带的有一对键值 headers 满足队列定义的多个参数 arguments 的其中一个就能匹配上,注意这里是键值对的院全匹配,只匹配到健了,值却不一样是不行的;
实上是一个由 RabbitMQ 预先声明好的名字为空字符申的直连交换机( direct exchange )·
它有一个特殊的属性使得它对于简单应用特别有用处:那就是每个新建队列( queue )都会自动綁定到认交换机上,綁定的路由键( routing key )名称与队列名称相同。
三.代码演示
注意:交换机与列队绑定时,方法名不能与其他的重复
1.直连 ①.Provider
(1).DirectConfig
package com.zxy.provider.mq;import org.springframework.amqp.core.Binding;import org.springframework.amqp.core.BindingBuilder;import org.springframework.amqp.core.DirectExchange;import org.springframework.amqp.core.Queue;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configuration@SuppressWarnings("all")public class DirectConfig { // 创建队列 @Bean public Queue directQueueA(){ return new Queue("directQueueA",true); } @Bean public Queue directQueueB(){ return new Queue("directQueueB",true); } @Bean public Queue directQueueC(){ return new Queue("directQueueC",true); } // 穿件交换机 @Bean public DirectExchange directExchange(){ return new DirectExchange("directExchange"); } // 进行交换机和队列的绑定,设置bindingkey @Bean public Binding BindingA(){ return BindingBuilder.bind(directQueueA()).to(directExchange()).with("AA"); } @Bean public Binding BindingB(){ return BindingBuilder.bind(directQueueB()).to(directExchange()).with("BB"); } @Bean public Binding BindingC(){ return BindingBuilder.bind(directQueueC()).to(directExchange()).with("CC"); }}
(2).ProviderController
package com.zxy.provider;import org.springframework.amqp.rabbit.core.RabbitTemplate;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@SuppressWarnings("all")public class ProviderController { @Autowired private RabbitTemplate template; @RequestMapping("/directSend") public String directSend(String routingKey){ template.convertAndSend("directExchange",routingKey,"Hello Wold"); return "yes"; }}
②.cunsumer
(1).DirectReceiverA
package com.zxy.consumer.mq;import lombok.extern.slf4j.Slf4j;import org.springframework.amqp.rabbit.annotation.RabbitHandler;import org.springframework.amqp.rabbit.annotation.RabbitListener;import org.springframework.stereotype.Component;@Component@SuppressWarnings("all")@RabbitListener(queues = "directQueueA")@Slf4jpublic class DirectReceiverA { @RabbitHandler public void process(String message){ log.info("A接到"+message); }}
(2).DirectReceiverB
package com.zxy.consumer.mq;import lombok.extern.slf4j.Slf4j;import org.springframework.amqp.rabbit.annotation.RabbitHandler;import org.springframework.amqp.rabbit.annotation.RabbitListener;import org.springframework.stereotype.Component;@Component@SuppressWarnings("all")@RabbitListener(queues = "directQueueB")@Slf4jpublic class DirectReceiverB { @RabbitHandler public void process(String message){ log.info("B接到"+message); }}
(3).DirectReceiverC
package com.zxy.consumer.mq;import lombok.extern.slf4j.Slf4j;import org.springframework.amqp.rabbit.annotation.RabbitHandler;import org.springframework.amqp.rabbit.annotation.RabbitListener;import org.springframework.stereotype.Component;@Component@SuppressWarnings("all")@RabbitListener(queues = "directQueueC")@Slf4jpublic class DirectReceiverC { @RabbitHandler public void process(String message){ log.info("C接到"+message); }}
2.主题 ①.Provider
(1)TopicConfig
package com.zxy.provider.mq;import org.springframework.amqp.core.*;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configuration@SuppressWarnings("all")public class TopicConfig { public final static String KEY_A="*.orange.*"; public final static String KEY_B="*.*rabbit"; public final static String KEY_C="lazy.#"; // 创建队列 @Bean public Queue topicQueueA(){ return new Queue("topicQueueA",true); } @Bean public Queue topicQueueB(){ return new Queue("topicQueueB",true); } @Bean public Queue topicQueueC(){ return new Queue("topicQueueC",true); } // 创建交换机 @Bean public TopicExchange topicExchange(){ return new TopicExchange("topicExchange"); } @Bean public Binding topicBindingA(){ return BindingBuilder.bind(topicQueueA()).to(topicExchange()).with(KEY_A); } @Bean public Binding topicBindingB(){ return BindingBuilder.bind(topicQueueB()).to(topicExchange()).with(KEY_B); } @Bean public Binding topicBindingC(){ return BindingBuilder.bind(topicQueueC()).to(topicExchange()).with(KEY_C); }}
(2).ProviderController
@RequestMapping("/topicSend") public String topicSend(String routingKey){ template.convertAndSend("topicExchange",routingKey," word"); return "yes"; }
②.consumer
(1).TopicReceiverA
package com.zxy.consumer.mq;import lombok.extern.slf4j.Slf4j;import org.springframework.amqp.rabbit.annotation.RabbitHandler;import org.springframework.amqp.rabbit.annotation.RabbitListener;import org.springframework.stereotype.Component;@Component@SuppressWarnings("all")@RabbitListener(queues = "topicQueueA")@Slf4jpublic class TopicReceiverA { @RabbitHandler public void process(String message){ log.warn("A接到"+message); }}
(2).TopicReceiverB
package com.zxy.consumer.mq;import lombok.extern.slf4j.Slf4j;import org.springframework.amqp.rabbit.annotation.RabbitHandler;import org.springframework.amqp.rabbit.annotation.RabbitListener;import org.springframework.stereotype.Component;@Component@SuppressWarnings("all")@RabbitListener(queues = "topicQueueB")@Slf4jpublic class TopicReceiverB { @RabbitHandler public void process(String message){ log.warn("B接到"+message); }}
(3).TopicReceiverC
package com.zxy.consumer.mq;import lombok.extern.slf4j.Slf4j;import org.springframework.amqp.rabbit.annotation.RabbitHandler;import org.springframework.amqp.rabbit.annotation.RabbitListener;import org.springframework.stereotype.Component;@Component@SuppressWarnings("all")@RabbitListener(queues = "topicQueueC")@Slf4jpublic class TopicReceiverC { @RabbitHandler public void process(String message){ log.warn("C接到"+message); }}
3.扇形 ①.provider
(1).FanoutConfig
package com.zxy.provider.mq; import org.springframework.amqp.core.Binding;import org.springframework.amqp.core.BindingBuilder;import org.springframework.amqp.core.FanoutExchange;import org.springframework.amqp.core.Queue;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration; @Configuration@SuppressWarnings("all") public class FanoutConfig { @Bean public Queue fanoutQueueA(){ return new Queue("fanoutQueueA",true); } @Bean public Queue fanoutQueueB(){ return new Queue("fanoutQueueB",true); } @Bean public Queue fanoutQueueC(){ return new Queue("fanoutQueueC",true); } @Bean public FanoutExchange fanoutExchange(){ return new FanoutExchange("fanoutExchange"); } @Bean public Binding fanoutBindingA(){ return BindingBuilder.bind(fanoutQueueA()).to(fanoutExchange()); } @Bean public Binding fanoutBindingB(){ return BindingBuilder.bind(fanoutQueueB()).to(fanoutExchange()); } @Bean public Binding fanoutBindingC(){ return BindingBuilder.bind(fanoutQueueC()).to(fanoutExchange()); } }
(2).ProviderController
@RequestMapping("/fanoutSend") public String fanoutSend(){ template.convertAndSend("topicExchange","null"," word me"); return "yes"; }
②.consumer(1).FanoutReceiverA
package com.zxy.consumer.mq; import lombok.extern.slf4j.Slf4j;import org.springframework.amqp.rabbit.annotation.RabbitHandler;import org.springframework.amqp.rabbit.annotation.RabbitListener;import org.springframework.stereotype.Component; @Component@SuppressWarnings("all")@RabbitListener(queues = "fanoutQueueA")@Slf4jpublic class FanoutReceiverA { @RabbitHandler public void process(String message){ log.info("C接到"+message); } }
(2).FanoutReceiverB
package com.zxy.consumer.mq; import lombok.extern.slf4j.Slf4j;import org.springframework.amqp.rabbit.annotation.RabbitHandler;import org.springframework.amqp.rabbit.annotation.RabbitListener;import org.springframework.stereotype.Component; @Component@SuppressWarnings("all")@RabbitListener(queues = "fanoutQueueB")@Slf4jpublic class FanoutReceiverB { @RabbitHandler public void process(String message){ log.info("C接到"+message); } }
(3).FanoutReceiverC
package com.zxy.consumer.mq; import lombok.extern.slf4j.Slf4j;import org.springframework.amqp.rabbit.annotation.RabbitHandler;import org.springframework.amqp.rabbit.annotation.RabbitListener;import org.springframework.stereotype.Component; @Component@SuppressWarnings("all")@RabbitListener(queues = "directQueueC")@Slf4jpublic class FanoutReceiverC { @RabbitHandler public void process(String message){ log.info("C接到"+message); } }