什么是RabbitMQ
RabbitMQ是一款开源的消息队列系统,它可以实现异步消息的发送和接收。RabbitMQ可以实现服务解耦,异步处理,定时任务(Spring Task也可以实现定时任务)等等。
在项目中遇到服务间耦合度过高的问题可以使用RabbitMQ
来解决。
什么是服务解耦呢?
通过消息队列实现不同服务间的解耦,提高系统的可拓展性和可维护性。
在实战案例中难免会遇到服务间耦合度过高的问题。
流程图:
举个常见的例子,在分布式电商项目中,我们通过ElasticSearch
(搜索引擎)来实现搜索功能并且查询出的数据是在ElasticSearch
中查询出来的,而在后台中我们修改商品信息或者新增商品信息,在ElasticSearch中商品信息并不会得到同步修改,也就是说修改商品之后会导致后台和前台的数据不一致,此时如果不用RabbitMQ
的话,想要解决此问题需要在后台商品服务中引入搜索服务,这样做也可以实现数据同步,但会造成一个问题,就是商品服务的启动必须依赖于搜索服务,这样会导致服务间耦合度太高了,这时可以使用RabbitMQ
来解决这一问题
代码参考如下
同步消息到ES中,删除ES中的数据,实现这两个功能,需要两个队列,一个是同步消息队列,一个是删除消息队列
这里我采用的交换机类型为(主题交换机也叫通配符模式topicExchange
),这个模式的交换机是根据通配符进行匹配的
这个模式的工作原理是我们将消息发送给交换机,交换机根据通配符将消息发送给对应的队列,在消费者那边通过RabbitListener
监听队列,就可以对消息进行一个消费了
安装RabbitMQ并开启管控台插件
- 安装docker
- 拉取RabbitMQ镜像
- 运行容器
- 进入容器开启管控台插件
- 浏览器访问:
http://ip地址:15672
# 使用yum源安装docker容器
yum install -y docker
# 拉取RabbitMQ镜像
docker pull rabbitmq:3.9
# 启动RabbitMQ镜像
docker run -id --hostname myrabbit --name=rabbitmq -p 5672:5672 -p 15672:15672 rabbitmq:3.9
# 进入容器并开启管控台插件
docker exec -it rabbitmq /bin/bash
rabbitmq-plugins enable rabbitmq_management
配置类
package com.itbaizhan.shopping_goods_service;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitConfig {
// 交换机
private final String GOODS_EXCHANGE = "goods_exchange";
// 同步消息队列
private final String SYNC_GOODS_QUEUE = "sync_goods_queue";
// 删除消息队列
private final String DEL_GOODS_QUEUE = "del_goods_queue";
@Bean(GOODS_EXCHANGE)
public Exchange getExchange (){
return ExchangeBuilder.topicExchange(GOODS_EXCHANGE)
.durable(true)
.build();
}
@Bean(SYNC_GOODS_QUEUE)
public Queue getQueue1(){
return new Queue(SYNC_GOODS_QUEUE);
}
@Bean(DEL_GOODS_QUEUE)
public Queue getQueue2(){
return new Queue(DEL_GOODS_QUEUE);
}
@Bean
public Binding exchangeToQueue1(@Qualifier(GOODS_EXCHANGE) Exchange exchange,
@Qualifier(SYNC_GOODS_QUEUE) Queue queue){
return BindingBuilder
.bind(queue)
.to(exchange)
.with("#.sync_goods.#")
.noargs();
}
@Bean
public Binding exchangeToQueue(@Qualifier(GOODS_EXCHANGE) Exchange exchange,
@Qualifier(DEL_GOODS_QUEUE) Queue queue){
return BindingBuilder
.bind(queue)
.to(exchange)
.with("#.del_goods.#")
.noargs();
}
}
生产者代码参考:
@Autowired
private RabbitTemplate rabbitTemplate;
@Override
public void add(Goods goods) {
// 新增商品数据
goodsMapper.insert(goods);
// 新增商品图片数据
Long goodsId = goods.getId();
List<GoodsImage> images = goods.getImages();
for (GoodsImage image : images) {
image.setGoodsId(goodsId);
goodsImageMapper.insert(image);
}
// 新增商品规格项数据
List<Specification> specifications = goods.getSpecifications();
List<SpecificationOption> specificationOptions = new ArrayList();
for (Specification specification : specifications) {
specificationOptions.addAll(specification.getSpecificationOptions());
}
for (SpecificationOption specificationOption : specificationOptions) {
goodsMapper.addGoodsSpecificationOption(goodsId,specificationOption.getId());
}
// 查询出商品详情将数据同步到es中
GoodsDesc desc = findDesc(goodsId);
// searchService.syncGoodsToEs(desc);
rabbitTemplate.convertAndSend("goods_exchange","sync_goods",desc);
}
@Override
public void update(Goods goods) {
// 删除旧图片数据
Long goodsId = goods.getId();
QueryWrapper<GoodsImage> queryWrapper = new QueryWrapper();
queryWrapper.eq("goodsId",goodsId);
goodsImageMapper.delete(queryWrapper);
// 删除旧规格项数据
goodsMapper.deleteGoodsSpecificationOption(goodsId);
// 新增商品数据
goodsMapper.updateById(goods);
// 新增商品图片数据
List<GoodsImage> images = goods.getImages();
for (GoodsImage image : images) {
image.setGoodsId(goodsId);
goodsImageMapper.insert(image);
}
// 新增商品规格项数据
List<Specification> specifications = goods.getSpecifications();
List<SpecificationOption> specificationOptions = new ArrayList();
for (Specification specification : specifications) {
specificationOptions.addAll(specification.getSpecificationOptions());
}
for (SpecificationOption specificationOption : specificationOptions) {
goodsMapper.addGoodsSpecificationOption(goodsId,specificationOption.getId());
}
GoodsDesc desc = findDesc(goodsId);
// searchService.syncGoodsToEs(desc);
rabbitTemplate.convertAndSend("goods_exchange","sync_goods",desc);
}
@Override
public Goods findById(Long id) {
return goodsMapper.findById(id);
}
@Override
public void putAway(Long id, Boolean isMarketable) {
goodsMapper.putAway(id,isMarketable);
// 上架时同步到es 下架时删除es中的的数据
if(isMarketable){
GoodsDesc goodsDesc = findDesc(id);
// searchService.syncGoodsToEs(goodsDesc);
rabbitTemplate.convertAndSend("goods_exchange","sync_goods",goodsDesc);
}else{
// searchService.delete(id);
rabbitTemplate.convertAndSend("goods_exchange","del_goods",id);
}
}
消费者代码参考:
// 监听同步消息队列
@RabbitListener(queues = "sync_goods_queue")
public void listenerQueue1(GoodsDesc goodsDesc){
syncGoodsToEs(goodsDesc);
}
// // 监听删除消息队列
@RabbitListener(queues = "del_goods_queue")
public void listenerQueue2(Long id){
delete(id);
}