目标:
从宏观上掌握RabbitMq这个消息中间件的基本原理。同时让阅读者掌握一些基本的使用方法。
大致原理介绍
为了实现解耦或者实现异步,将消息先发往独立于应用服务以外的一个中间服务(也就是mq)存储,其他服务在从这个中间服务获取消息,进行接下来的业务逻辑处理。整体流程如下:
消息中间件的作用
市场上包括各种中间件Kafka、RabbitMq、ActiveMq、RocketMq等。作用其实都是类似
- 解耦
- 流量削峰
- 异步通信
- 冗余、扩展、缓冲等
中间件的安装
RabbitMq的整体架构分析
相关名词介绍:
- producer :生产者,可以理解为发送消息的一方
- consumer:消费者,可以理解为处理消息的一方
- broker:消息中间件服务,消息的中间方。安装mq服务的节点。
消息的流转过程
其他关键名词介绍:
- 交换机:可以理解为一个路由器,整个消息进度broker的第一个处理者。根据消息的不同,将消息放入不同的队列。
- 路由键:标志消息属于哪个队列(某些情况下该参数失效)
- 绑定: 将交换机和队列进行绑定,
- 队列:整个mq服务端(发送消息和消费消息的是客户端)用于存储消息的对象;
交换机类型
其实就是介绍交换机的常见模式。有一对一,也有一对多
1、fanout:可以理解为组播
凡是绑定在交换机下的队列都能收到消息。一个交换机会绑定很多个队列,这种情况下路由键会失效。
2、direct:完全根据路由key进行路由
可以看到路由键为warning的话,消息会被推到两个队列;路由key是info的话只会进入一个队列。这个就是direct类型的交互器的特征。
3、topic:绑定的key带有通配符
路由键带有通配符
4、head
实际使用介绍
实际使用介绍之前,我们先介绍下“连接”和“信道”的概念
生产者在和mq服务通信过程中是通过TCP协议,那个二者之间就会建立tcp连接,这种连接的建立通常是非常耗费时间,所以mq的设计者就使用了复用tcp连接的思路。那channel又是什么呢?他的中文翻译是信道,这个信道我们可以理解为完成一次逻辑通信的对象。比如我们可以是整个生产者服务和mq之间只有一条TCP链路,但是生产者可以是多线程的,多线程各自维护了一个和Mq服务通信的信道,也就是这里的channl ,chanel是一条逻辑上的通信链路。Connection是一条物理上的通信链路。
那为什么不直接使用Connection呢?主要是考虑各个线程之间的数据隔离
是不是无论多少个信道都可以共用一个Connection呢?不是,当信道数量越来越多的时候,一个Tcp连接可能不够用,我们应该适当的增加物理连接的数量。
最简单使用
默认交换机的使用
# 配置类
@Configuration
//@ConditionalOnProperty(prefix = SystemProperties.PREFIX, name = "openRabbitMq", havingValue = "true", matchIfMissing = true)
public class RabbitMqConfiguration {
@Bean
CommonConsumer commonConsumer(){
return new CommonConsumer(); //申明一个默认消费者,
}
@Bean //定义一个普通队列,并没有给整个队列绑定交换机哦!
public Queue commonQueue() {
return new Queue(QueueEnum.COMMON_QUEUE.getQueueName());
}
@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(CachingConnectionFactory connectionFactory, MessageConverter messageConverter) {
connectionFactory.setPublisherConfirms(true);
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
factory.setConnectionFactory(connectionFactory);
factory.setMessageConverter(messageConverter);
return factory;
}
@Bean
public MessageConverter messageConverter() {
//申明对象序列化类
return new ContentTypeDelegatingMessageConverter(new Jackson2JsonMessageConverter());
}
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, MessageConverter messageConverter) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
template.setMessageConverter(messageConverter);
template.setMandatory(true);
return template;
}
}
## 生产者
package com.defire.provider;
// 实现了 InitializingBean的对象在bean初始化时会调用afterPropertiesSet方法。
//ConfirmCallback & 和ReturnCallback 是为了实现消息确认机制,保证整个中间件的高可用。我们后文还会深入探讨
@Compon