Redis缓存预热如何实现?

Hello,小伙伴们大家好,今天给大家分享一下如何实现Redis的缓存预热。

技术栈:

SpringBoot 3.0.2

Redis4

MySQL8

Mybatis-Plus 3.5.3.1

Druid 1.2.18

工具:

lombok

什么是缓存预热?

缓存预热是一种在程序启动或缓存失效之后,主动将热点数据加载到缓存中的策略。 这样,在实际请求到达程序时,热点数据已经存在于缓存中,从而减少了缓存穿透和缓存击穿的情况,也缓解了SQL服务器的压力。

实现

缓存抽象类

首先我们先来实现一个缓存抽象类,这个抽象类的作用就是在将来我们需要将某个模块的数据需要提前加载到缓存中的时候,我们可以创建一个它的实现类,来进行数据的缓存与加载,具体使用方式请看后边我写的例子。

java 复制代码
public abstract class AbstractCache {

    /**
     * 缓存
     */
    protected abstract void init();

    /**
     * 获取缓存
     *
     * @param <T>
     * @return
     */
    public abstract <T> T get();

    /**
     * 清理缓存
     */
    public abstract void clear();

    /**
     * 重新加载
     */
    public void reload() {
        clear();
        init();
    }
}

Spring上下文工具类

接下来我们实现一个Spring的上下文工具类,这个工具类需要实现ApplicationContextAware,作用就是负责管理bean的加载与实例化的,具体如何使用,请往下继续阅读。

java 复制代码
@Component
public class ApplicationContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextUtil.applicationContext = applicationContext;
    }

    /**
     * 获取上下文
     * @return
     */
    public static ApplicationContext getContext() {
        return applicationContext;
    }
}

缓存预热

然后我们来实现,在程序启动后,直接进行数据的缓存加载,这个类需要实现CommandLineRunner接口,这个接口提供的方法作用就是在程序启动后自动运行。这个实现类里,我们使用ApplicationContextUtil工具类来获取上下文,然后通过getBeansOfType方法获取实现AbstractCache抽象类的子类,返回的是一个Map类型的集合,接下来通过getBean方法以多态的方式实例化子类,最后我们调用抽象类的init方法即可。如果有多个实现类,使用@Order注解标注先后运行就可以了。

java 复制代码
@Component
@ConditionalOnProperty(name = {"cache.init.enable"}, havingValue = "true", matchIfMissing = false)
public class CachePreheatHandler implements CommandLineRunner {

    /**
     * 缓存预热
     * @param args
     * @throws Exception
     */
    @Override
    public void run(String... args) throws Exception {
        ApplicationContext context = ApplicationContextUtil.getContext();
        Map<String, AbstractCache> beansOfType = context.getBeansOfType(AbstractCache.class);
        for (Map.Entry<String, AbstractCache> cacheEntry : beansOfType.entrySet()) {
            AbstractCache cache = context.getBean(cacheEntry.getValue().getClass());
            cache.init();
        }
    }

}

⚠️解释:
@ConditionalOnProperty这个注解在这里的作用是,需要在配置文件开启cache.init.enable,理想值是true,默认值是false

properties 复制代码
cache.init.enable=true

使用

我们就以新闻热点为例,数据库中有一张tb_news新闻表,均为微博热搜体育榜内容。

接下来创建一个AbstractCache的实现类,来实现具体的实现

java 复制代码
@Component
@RequiredArgsConstructor
public class NewsCache extends AbstractCache {

    private static final String NEWS_KEY = "news";

    private final RedisTemplate<String, Object> redisTemplate;

    private final NewsService newsService;

    @Override
    protected void init() {
        if (Boolean.FALSE.equals(redisTemplate.hasKey(NEWS_KEY))) {
            redisTemplate.opsForValue().set(NEWS_KEY, newsService.list(), 30, TimeUnit.MINUTES);
        }
    }

    @Override
    public <T> T get() {
        if (Boolean.FALSE.equals(redisTemplate.hasKey(NEWS_KEY))) {
            reload();
        }
        return (T) redisTemplate.opsForValue().get(NEWS_KEY);
    }

    @Override
    public void clear() {
        redisTemplate.delete(NEWS_KEY);
    }
}

然后启动项目,我们就发现,Redis中已经存好了热点数据

最后可以通过get方法获取数据了,也不用担心数据过期了。

java 复制代码
@RestController
@RequestMapping("/news")
@RequiredArgsConstructor
public class NewsController {

    private final NewsCache newsCache;

    @GetMapping("/cache")
    public List<News> list() {
        return newsCache.get();
    }

}

好了,小伙伴们,今天的分享就到此结束了,欢迎留出建议,如果觉得内容可以,还请来个点赞和关注吧!

此致!!!

相关推荐
星浩AI19 小时前
Google 官方发布:让你的 AI 编程助手"边写、边看、边调",像人类开发者一样工作
人工智能·后端·开源
焰火199919 小时前
[Java]自定义重试工具类
java
喵了个Code19 小时前
Spring Boot 3 + Spring Security + OAuth2 + Gateway企业级认证授权平台实现
后端
开心猴爷19 小时前
除了 Perfdog,如何在 Windows 环境中完成 iOS App 的性能测试工作
后端
SuperherRo20 小时前
JAVA攻防-Shiro专题&断点调试&有key利用链&URL&CC&CB&原生反序列化&加密逻辑
java·shiro·反序列化·有key·利用链·原生反序列化·加密逻辑
桦说编程20 小时前
简单方法实现子任务耗时统计
java·后端·监控
爱笑的眼睛1120 小时前
超越可视化:降维算法组件的深度解析与工程实践
java·人工智能·python·ai
盖世英雄酱5813620 小时前
物品超领取损失1万事故复盘(一)
java·后端
凌览20 小时前
别再死磕 Nginx!http-proxy-middleware 低配置起飞
前端·后端