一. RabbitMQ架构分析
一、订阅模式(Fanout Exchange)
一个生产者,多个消费者,每一个消费者都有自己的一个队列,生产者没有将消息直接发送到队列,而是发送到了交换机,每个队列绑定交换机,生产者发送的消息经过交换机,到达队列,实现一个消息被多个消费者获取的目的。需要注意的是,如果将消息发送到一个没有队列绑定的exchange上面,那么该消息将会丢失,这是因为在rabbitMQ中exchange不具备存储消息的能力,只有队列具备存储消息的能力,类似子网广播,交换机,以广播的形式,不处理路由键,将消息发送到每个绑定的队列,Fanout Exchange 转发消息是最快的。
spring boot 示例代码:
配置交换机绑定队列
@Configuration
public class RabbitConfig {
@Bean
FanoutExchange addfanoutExchange() {
return new FanoutExchange(Constants.RABBIT_DATAMAP);
}
@Bean
public Queue imageHouseMessage(){
return new Queue(Constants.RABBIT_DATAMAP+".imageHouse");
}
@Bean
public Queue normalHouseMessage(){
return new Queue(Constants.RABBIT_DATAMAP+".normalHouse");
}
@Bean
Binding bindingExchangeAddimageHouseMessage(Queue imageHouseMessage, FanoutExchange addfanoutExchange) {
return BindingBuilder.bind(imageHouseMessage).to(addfanoutExchange);
}
@Bean
Binding bindingExchangeAddnormalHouseMessage(Queue normalHouseMessage, FanoutExchange addfanoutExchange) {
return BindingBuilder.bind(normalHouseMessage).to(addfanoutExchange);
}
}
生产者
@Component
public class RabbitProductorTemplate {
@Autowired
private RabbitTemplate rabbitTemplate;
public void publish(){
rabbitTemplate.convertAndSend(Constants.RABBIT_DATAMAP, "", new HashMap<>());
}
}
消费者
@RabbitListener(queues ="startspush_dataMap.normalHouse")
public class RabbitSubscribeTemplate {
@Autowired
private RabbitTemplate rabbitTemplate;
@RabbitHandler
private void process(Map<String,Object> dataMap){
}
}
二、路由模式(Direct Exchange)
这种模式添加了一个路由键,生产者发布消息的时候添加路由键,消费者绑定队列到交换机时添加键值,这样就可以接收到需要接收的消息,路由交换机根据路由键精确匹配绑定键然后投递到绑定队列中,允许多绑定方式,拥有扇形交换机的能力同时支持精确路由。
@Configuration
public class RabbitConfig {
@Bean
FanoutExchange addfanoutExchange() {
return new FanoutExchange(Constants.RABBIT_DATAMAP);
}
@Bean
public Queue imageHouseMessage(){
return new Queue(Constants.RABBIT_DATAMAP+".imageHouse");
}
@Bean
public Queue normalHouseMessage(){
return new Queue(Constants.RABBIT_DATAMAP+".normalHouse");
}
@Bean
Binding bindingExchangeAddimageHouseMessage(Queue imageHouseMessage, FanoutExchange addfanoutExchange) {
return BindingBuilder.bind(imageHouseMessage).to(addfanoutExchange);
}
@Bean
Binding bindingExchangeAddnormalHouseMessage(Queue normalHouseMessage, FanoutExchange addfanoutExchange) {
return BindingBuilder.bind(normalHouseMessage).to(addfanoutExchange);
}
}
生产者根据路由Key交换机转发不同队列。
@Component
public class RabbitProductorTemplate {
@Autowired
private RabbitTemplate rabbitTemplate;
public void publish(){
rabbitTemplate.convertAndSend(Constants.RABBIT_DATAMAP, "normal", new HashMap<>());
rabbitTemplate.convertAndSend(Constants.RABBIT_DATAMAP, "image", new HashMap<>());
}
}
监听消费normal队列
@RabbitListener(queues ="startspush_dataMap.normalHouse")
public class RabbitSubscribeTemplate {
@Autowired
private RabbitTemplate rabbitTemplate;
@RabbitHandler
private void process(Map<String,Object> dataMap){
}
}
监听消费image队列
@RabbitListener(queues ="startspush_dataMap.imageHouse") public class RabbitSubscribeTemplate { @Autowired private RabbitTemplate rabbitTemplate; @RabbitHandler private void process(Map<String,Object> dataMap){ } }
二、主题交换机(Topic Exchange)
发送到主题交换机(topic exchange)的消息不可以携带随意什么样子的路由键(routing_key),它的路由键必须是一个由.
分隔开的词语列表。这些单词随便是什么都可以,但是最好是跟携带它们的消息有关系的词汇。以下是几个推荐的例子:"stock.usd.nyse", "nyse.vmw", "quick.orange.rabbit"。词语的个数可以随意,但是不要超过255字节。
绑定键也必须拥有同样的格式。主题交换机背后的逻辑跟直连交换机很相似 —— 一个携带着特定路由键的消息会被主题交换机投递给绑定键与之想匹配的队列。但是它的绑定键和路由键有两个特殊应用方式:
*
(星号) 用来表示一个单词.#
(井号) 用来表示任意数量(零个或多个)单词。
主题交换机是很强大的,它可以表现出跟其他交换机类似的行为
当一个队列的绑定键为 "#"(井号) 的时候,这个队列将会无视消息的路由键,接收所有的消息。
当 *
(星号) 和 #
(井号) 这两个特殊字符都未在绑定键中出现的时候,此时主题交换机就拥有的直连交换机的行为。
@Configuration
public class RabbitTopicConfig {
@Bean
TopicExchange addTopicExchange() {
return new TopicExchange(Constants.RABBIT_DATAMAP);
}
@Bean
public Queue imageHouseMessage() {
return new Queue(Constants.RABBIT_DATAMAP + ".imageHouse");
}
@Bean
public Queue normalHouseMessage() {
return new Queue(Constants.RABBIT_DATAMAP + ".normalHouse");
}
@Bean
Binding bindingExchangeAddimageHouseMessage(Queue imageHouseMessage, TopicExchange addTopicExchange) {
return BindingBuilder.bind(imageHouseMessage).to(addTopicExchange).with("*.orange.*");
}
@Bean
Binding bindingExchangeAddnormalHouseMessage(Queue normalHouseMessage, TopicExchange addTopicExchange) {
return BindingBuilder.bind(normalHouseMessage).to(addTopicExchange).with("*.*.rabbit*,*.orange.*");
}
}
生产者根据路由不同队列。
@Component
*.*.rabbit*,*.orange.*,*.orange.*
public class RabbitProductorTemplate {
@Autowired
private RabbitTemplate rabbitTemplate;
public void publish(){
rabbitTemplate.convertAndSend(Constants.RABBIT_DATAMAP, "", new HashMap<>());
}
}
监听消费normal队列
@RabbitListener(queues ="startspush_dataMap.normalHouse")
public class RabbitSubscribeTemplate {
@Autowired
private RabbitTemplate rabbitTemplate;
@RabbitHandler
private void process(Map<String,Object> dataMap){
}
}