前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >项目实践缓存预热方案之CommandLineRunner和ApplicationRunner

项目实践缓存预热方案之CommandLineRunner和ApplicationRunner

作者头像
xdd
发布2022-07-12 14:21:00
6200
发布2022-07-12 14:21:00
举报
文章被收录于专栏:java技术鸡汤

众所周知,在项目的开发中,合理使用缓存是提高服务性能的一大利器,本篇文章就来介绍一下我所在项目中如何使用缓存的一个案例。

背景

我们的项目是由多个微服务所组成,业务是保险,我所负责的模块是出单,在压测的过程中,发现当所有服务启动好之后,第一次出单的时间存在耗时较长的情况,通过sleuth分析了一下各个服务之间的调用链,针对第一单,发现出单接口中存在调用其他接口做查询和逻辑处理,在第一次调用后会将结果缓存,那么以后的调用基本是直接走缓存,不会去和数据库交互,减少了数据库创建和关闭连接之类的耗时。此时,我发现针对首单慢的问题,主要是因为一些接口返回固定的值,第一次没有通过缓存获取而导致的耗时较长的问题。

解决方案

为了解决首单耗时较长的问题,我采用了缓存预热的方案,那就是在服务启动的时候进行缓存预热,这样首单中一些接口的调用也是会通过缓存来取值,肯定是可以减少耗时,提高接口的性能,缩短出单的时间。

缓存预热

  • 不是所有的接口都需要进行缓存预热,应该按照自己的业务所需对缓存预热谨慎使用
  • 对缓存预热应该是同步还是异步进行,这个需要考虑
    • 缓存预热同步,那么服务启动好之后缓存预热也结束了,正常的业务就可以开始进行
    • 缓存预热异步,服务虽然启动好了,但是缓存预热可能还在进行中,是否会影响到自己的业务需要考虑一下
    • 相对比较而言,同步预热会拉长服务的启动时间,异步预热不会拉长服务的启动时间
项目实践

具体的相关代码如下所示:

代码语言:javascript
复制
package com.xxx.xxx.xx.xxx.service.inner.impl;


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.List;

import static java.util.stream.Collectors.toList;

/**
 * xxx 服务启动时 加载缓存  缓存项为vvv的内容
 * @author xxx
 */
@Order(4)
@Component
@Slf4j
public class InitMarketCacheService implements CommandLineRunner {

    @Value("#{'${zz.xx.goodsId}'.split(',')}")
    private List<String> goodsIdArray;
    @Value("#{'${zz.xx.planId}'.split(',')}")
    private List<String>  planIdArray;
    @Value("#{'${zz.xx.productId}'.split(',')}")
    private List<String>  productIdArray;

    @Autowired
    private AxxService axxShareService;

    @Autowired
    private BxxShareService bxxShareService;


    @Override
    public void run(String... args) throws Exception {
        List<Long> goodsIdList = goodsIdArray.stream().map(Long::valueOf).collect(toList());
        List<Long> goodsPlanIdList = planIdArray.stream().map(Long::valueOf).collect(toList());
        List<Long> productIdList = productIdArray.stream().map(Long::valueOf).collect(toList());
        log.warn("begin init xxservice cache");
        try {
            for (Long goodsId:goodsIdList){
                AxxService.queryGoods(goodsId);
            }
            for (Long planId:goodsPlanIdList){
                AxxService.queryPlanAndPackage(planId);
            }
            for (Long productId:productIdList){
                BxxShareService.detail(productId);
            }
        }catch (Exception e){
            log.error("cache warm up failed",e);
        }finally {
            log.warn("end init xxx service cache");
        }
    }
}
相关知识点说明

CommandLineRunner

源码如下:

代码语言:javascript
复制
package org.springframework.boot;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

public interface CommandLineRunner {
  void run(String... args) throws Exception;
}

ApplicationRunner

源码如下:

代码语言:javascript
复制
package org.springframework.boot;

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;

public interface ApplicationRunner {
  void run(ApplicationArguments args) throws Exception;
}

CommandLineRunnerApplicationRunner

  • 区别:
    • CommandLineRunnerrun方法的参数是一个可变参数列表

    ApplicationRunnerrun方法的参数是一个ApplicationArguments类型的参数

  • 共同点:
    • 都是一个接口interface
    • 里面都有一个run()方法,返回值为void
    • 所有实现这两个接口的Beanspring boot启动后会自动调用
    • 可以定义多个Bean实现接口,但是调用的顺序可以使用@Order注解来指定,其中value属性的值越小,则会优先被调用
注意点

实现这两个接口的类,在执行run方法的时候默认是通过主线程的,如果在服务调用的时候,某个服务异常,那么该服务就会启动不起来,为了不影响服务的正常启动,我们可以采用try...catch的方法对执行run时的异常进行捕获,这样就不会影响服务的正常启动。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-10-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 java技术鸡汤 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 解决方案
  • 项目实践
  • 相关知识点说明
  • 注意点
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档