rabbitmq介绍
MQ全称Message Queue,即消息队列,RabbitMQ是由relang语言开发,基于AMQP(Advanced Message Queuing Protocol 一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计),它是一种应用程序之间的通信方法,消息队列在分布式系统开发中应用的非常广泛。
JMS是什么
JMS是java提供的一套消息服务API标准,其目的是为所有的java应用程序提供统一的消息通信的标准,类似java的 jdbc,只要遵循jms标准的应用程序之间都可以进行消息通信。它和AMQP有什么 不同,jms是java语言专属的消息服务标准,它是在api层定义标准,并且只能用于java应用;而AMQP是在协议层定义的标准,是跨语言的 。
开发过程中消息队列的应用场景
- 任务异步处理
将不需要同步处理的并且耗时长的操作由消息队列通知消息接收方进行异步处理。提高了应用程序的响应时间。 - 应用程序解耦合
MQ相当于一个中介,生产方通过MQ与消费方交互,它将应用程序解耦合
为什么使用RabbitMQ
- 使用简单,功能强大
- 基于AMQP协议
- 社区活跃,文档完善
- 高并发性能好,这主要得益于Erlang语言
- Spring Boot 默认已集成RabbitMQ
RabbitMQ的工作原理
RabbitMQ的基本结构:
组件部分说明如下:
- Producer:消息生产者,即生产方客户端,生产方客户端将消息发送到MQ。
- Broker:消息队列服务进程,此进程包括两个部分:Exchange和Queue。
- Exchang:消息队列交换机,按一定的规则将消息路由转发到某个队列,对消息进行过滤。
- Queue:消息队列,储存消息的队列,消息到达队列并转发给指定的消费方。
- Consumer:消息消费者,即消费方客户端,接收MQ转发的消息。
消息发布接收流程:
–发送消息–
- 生产者 和Broker建立TCP连接
- 生产者和Broker 建立通道
- 生产者通过通道消息发送给Broker,由Exchange将消息进行转发。( 声明队列 )
- Exchange将消息转发到指定的Queue队列。( 发送消息)
–接收消息–
- 消费者和Broker简历TCP连接。( 创建连接)
- 消费者和Broker建立通道( 创建通道)
- 消费者监听指定的Queue(队列)( 声明队列)
- 当有消息到达Queue时Broker默认将消息推送给消费者( 监听队列)
- 消费者接收到消息( 接收消息)
rabbitMQ有以下几种工作模式
- work queues
- publish/subscribe
- routing
- topics
- headers
- rpc
在项目中的使用
系统管理发布页面-发送消息给mq消息队列-门户服务器接收消息然后从gridfs获取页面-门户得到发布的课程资源
流程
创建消费方并部署在多个服务器上,它负责接收到页面发布的消息后从GridFS中下载文件在本地保存。
- 配置交换机、队列名称和路由key(站点ID)。
@Configuration
public class RabbitmqConfig {
//队列的名称
public static final String QUEUE_CMS_POSTPAGE = "queue_cms_postpage";
//交换机的名称
public static final String EX_ROUTING_CMS_POSTPAGE="ex_routing_cms_postpage";
//队列的名称
@Value("${xuecheng.mq.queue}")
public String queue_cms_postpage_name;
//routingKey 即站点Id
@Value("${xuecheng.mq.routingKey}")
public String routingKey;
/**
* 交换机配置使用direct类型
* @return the exchange
*/
@Bean(EX_ROUTING_CMS_POSTPAGE)
public Exchange EXCHANGE_TOPICS_INFORM() {
return ExchangeBuilder.directExchange(EX_ROUTING_CMS_POSTPAGE).durable(true).build();
}
//声明队列
@Bean(QUEUE_CMS_POSTPAGE)
public Queue QUEUE_CMS_POSTPAGE(){
Queue queue = new Queue((queue_cms_postpage_name));
return queue;
}
/**
* 绑定队列到交换机
*
* @param queue the queue
* @param exchange the exchange
* @return the binding
*/
@Bean
public Binding BINDING_QUEUE_INFORM_SMS(@Qualifier(QUEUE_CMS_POSTPAGE) Queue queue,
@Qualifier(EX_ROUTING_CMS_POSTPAGE) Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(routingKey).noargs();
}
}
- 连接RabbitMQ并监听各自的“队列”。接收页面发布队列的消息。
@Component
public class ConsumerPostPage {
//日志
private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerPostPage.class);
@Autowired
CmsPageRepository cmsPageRepository;
@Autowired
PageService pageService;
@RabbitListener(queues={"${xuecheng.mq.queue}"})
public void postPage(String msg){
//解析消息
Map map=JSON.parseObject(msg, Map.class);
LOGGER.info("recieve cms post page:{}",msg.toString());
//取出页面id
String pageId=(String) map.get("pageId");
//查询页面信息
Optional<CmsPage> optional = cmsPageRepository.findById(pageId);
if(!optional.isPresent()){
LOGGER.error("recieve post msg is null:{}", msg.toString());
return;
}
//将页面保存到服务器的物理路径
pageService.savePageToServerPath(pageId);
}
}
- 根据消息(页面id)从mongodb数据库下载页面到本地
//将页面保存到服务器的物理路径
pageService.savePageToServerPath(pageId);
cms系统作为页面发布的生产方
- 前端请求cms页面发布接口
- 、cms页面发布接口执行页面静态化,并将静态化页面存储至GridFS中。
- 静态化成功后,向消息队列发送页面发布的消息。
//页面发布
public ResponseResult post(String pageId){
//执行页面静态化
String pageHtml = this.getPageHtml(pageId);
//将静态化文件存储到gridFs中
CmsPage cmsPage = saveHtml(pageId, pageHtml);
//向MQ发消息
sendPostPage(pageId);
return new ResponseResult(CommonCode.SUCCESS);
}
- 配置交换机
@Configuration
public class RabbitmqConfig {
//交换机的名称
public static final String EX_ROUTING_CMS_POSTPAGE="ex_routing_cms_postpage";
/**
* 交换机配置使用direct类型
* @return the exchange
*/
@Bean(EX_ROUTING_CMS_POSTPAGE)
public Exchange EXCHANGE_TOPICS_INFORM() {
return ExchangeBuilder.directExchange(EX_ROUTING_CMS_POSTPAGE).durable(true).build();
}
}
- 获取页面的信息及页面所属站点ID。
- 设置消息内容为页面ID。(采用json格式,方便日后扩展)
- 发送消息给ex_cms_postpage交换机,并将站点ID作为routingKey。
//向mq發消息
public void sendPostPage(String pageId){
//得到頁面信息
CmsPage cmsPage = this.getById(pageId);
if(cmsPage==null){
ExceptionCast.cast(CmsCode.INVALID_PARAM);
}
//创建消息对象
Map<String, String> msg = new HashMap<>();
msg.put("pageId", pageId);
//转成json串
String jsonString = JSON.toJSONString(msg);
//发送给mq
String siteId = cmsPage.getSiteId();
rabbitTemplate.convertAndSend(RabbitmqConfig.EX_ROUTING_CMS_POSTPAGE,siteId, jsonString );
}