乐优商城--服务--优化搜索微服务和页面微服务

1. 消息队列-Rabbitmq

结合前面所说的问题:

  • 商品服务对商品增删改以后,无需去操作索引库或静态页面,只是发送一条消息,也不关心消息被谁接收。
  • 搜索服务和静态页面服务接收消息,分别去处理索引库和静态页面。

如果以后有其它系统也依赖商品服务的数据,同样监听消息即可,商品服务无需任何代码修改。我们采用 消息队列 :Rabbit

2. 项目改造

接下来,我们使用xiao就改造项目,实现搜索服务、商品静态页的数据同步。

2.1 思路分析

| 发送方:商品微服务

  • 什么时候发?
    当商品服务对商品进行写操作:增、删、改的时候,需要发送一条消息,通知其它服务。
  • 发送什么内容?
    对商品的增删改时其它服务可能需要新的商品数据,但是如果消息内容中包含全部商品信息,数据量太大,而且并不是每个服务都需要全部的信息。因此我们只发送商品id,其它服务可以根据id查询自己需要的信息。

| 接收方:搜索微服务、静态页微服务

  • 接收消息后如何处理?
    • 搜索微服务:
      • 增/改:添加新的数据到索引库
      • 删:删除索引库数据
    • 静态页微服务:
      • 增:创建新的静态页
      • 删:删除原来的静态页
      • 改:创建新的静态页并删除原来的

2.2 商品微服务发送消息

我们先在商品微服务ly-item-service中实现发送消息。

2.2.1 引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

2.2.1 配置文件

我们在application.yml中添加一些有关RabbitMQ的配置:
在这里插入图片描述

  • template:有关AmqpTemplate的配置
    • retry:失败重试
      • enabled:开启失败重试
      • initial-interval:第一次重试的间隔时长
      • max-interval:最长重试间隔,超过这个间隔将不再重试
      • multiplier:下次重试间隔的倍数,此处是2即下次重试间隔是上次的2倍
    • exchange:缺省的交换机名称,此处配置后,发送消息如果不指定交换机就会使用这个
  • publisher-confirms:生产者确认机制,确保消息会正确发送,如果发送失败会有错误回执,从而触发重试

2.2.3 改造GoodsService

封装一个发送消息到mq的方法:

private void sendMessage(Long id, String type){
     // 发送消息
     try {
         this.amqpTemplate.convertAndSend("item." + type, id);
     } catch (Exception e) {
         logger.error("{}商品消息发送异常,商品id:{}", type, id, e);
     }
}
  • 这里没有指定交换机,因此默认发送到了配置中的:ly.item.exchange

注意:这里要把所有异常都try起来,不能让消息的发送影响到正常的业务逻辑

然后在新增的时候调用:
在这里插入图片描述
修改的时候调用:
在这里插入图片描述

2.3 搜索服务接收消息

搜索服务接收到消息后要做的事情:

  • 增:添加新的数据到索引库
  • 删:删除索引库数据
  • 改:修改索引库数据

因为索引库的新增和修改方法是合二为一的,因此我们可以将这两类消息一同处理,删除另外处理。

2.3.1 引入依赖

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-amqp</artifactId>
 </dependency>

2.3.2 添加配置

在这里插入图片描述
这里只是接收消息而不发送,所以不用配置template相关内容。

2.3.3 编写监听器

在这里插入图片描述
代码:

@Component
public class ItemListener {

    @Autowired
    private SearchService searchService;

    // 处理insert和update的消息
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "search.item.insert.queue",durable = "true"),
            exchange = @Exchange(name = "ly.item.exchange",type = ExchangeTypes.TOPIC),
            key = {"item.insert","item.update"}
    ))
    public void listenInsertOrUpdate(Long spuId){
        if(spuId == null)
            return;
        //处理消息,对索引库进行新增或修改
        searchService.createOrUpdateIndex(spuId);
    }

    // 处理delete的消息
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "search.item.delete.queue",durable = "true"),
            exchange = @Exchange(name = "ly.item.exchange",type = ExchangeTypes.TOPIC),
            key = {"item.delete"}
    ))
    public void listenDelete(Long spuId){
        if(spuId == null)
            return;
        //处理消息,对索引库进行删除
        searchService.deleteIndex(spuId);
    }
}

注: 普通类想注入到Spring中,得加上@Component 注解。

2.3.4 编写创建和删除索引方法

这里因为要创建和删除索引,我们需要在SearchService中拓展两个方法,创建和删除索引:

// 对索引库进行新增或修改
 public void createOrUpdateIndex(Long spuId) {
     // 查询spu
     Spu spu = goodsClient.querySpuById(spuId);
     // 构建goods
     Goods goods = buildGoods(spu);
     // 存入索引库
     repository.save(goods);

 }

 // 对索引库进行删除
 public void deleteIndex(Long spuId) {
     repository.deleteById(spuId);
 }

创建索引的方法可以从之前导入数据的测试类中拷贝和改造。

2.4 静态页服务接收消息

商品静态页服务接收到消息后的处理:

  • 增:创建新的静态页
  • 删:删除原来的静态页
  • 改:创建新的静态页并删除原来的

不过,我们编写的创建静态页的方法也具备覆盖以前页面的功能,因此:增和改的消息可以放在一个方法中处理,删除消息放在另一个方法处理。

2.4.1 引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

2.4.2 添加配置

spring:
  rabbitmq:
    host: 192.168.184.130
    username: leyou
    password: leyou
    virtual-host: /leyou

这里只是接收消息而不发送,所以不用配置template相关内容。

2.4.3 编写监听器

在这里插入图片描述
代码:

@Component
public class ItemListener {

    @Autowired
    private PageService pageService;

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "page.item.insert.queue",durable = "true"),
            exchange = @Exchange(name = "ly.item.exchange",type = ExchangeTypes.TOPIC),
            key = {"item.insert","item.update"}
    ))
    public void listenInsertOrUpdate(Long spuId){
        if(spuId == null)
            return;
        //处理消息,创建静态页
       pageService.createHtml(spuId);
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "page.item.delete.queue",durable = "true"),
            exchange = @Exchange(name = "ly.item.exchange",type = ExchangeTypes.TOPIC),
            key = {"item.delete"}
    ))
    public void listenDelete(Long spuId){
        if(spuId == null)
            return;
        //处理消息,对静态页进行删除
        pageService.deleteHtml(spuId);
    }
}

2.4.4 添加删除页面方法

这里因为要创建和删除html页面,我们需要在PageService中拓展这两个方法,由于创建
页面之前已做过,因此这里只写删除页面。

// 删除html页面
public void deleteHtml(Long spuId) {
   File dest = new File("E:\\course\\JavaProject\\upload", spuId + ".html");

   if(dest.exists()){
       dest.delete();
   }
}

2.4.5 部署到虚拟机

静态页部署到 nginx上:打成jar包,上传到虚拟机上;

  • 运行: java -jar ly-page.jar
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值