Redis数据预热实现

缓存预热是指在 Spring Boot 项目启动时,预先将数据加载到缓存系统(如 Redis)中的一种机制。它可以通过监听 ContextRefreshedEvent 或 ApplicationReadyEvent 启动事件,或使用 @PostConstruct 注解,或实现 CommandLineRunner 接口、ApplicationRunner 接口,和 InitializingBean 接口的方式来完成

1. CommandLineRunner接口

CommandLineRunner 是 Spring Boot 提供的一个接口,用于在应用程序启动后立即执行一些特定的代码。实现这个接口的类会在 Spring 容器启动完成并且所有 Bean 都已初始化后执行 run 方法

实现CommandLineRunner接口的类需要被Spring容器扫描到,可以使用@Component注解或其他方式将其注册为Spring Bean

先后顺序示例 可以通过@Order()来设置Runner的先后顺序,在上面例子的基础上增加

image-20240606203435874

2. Redis数据预热实现

@Slf4j
@Component
@RequiredArgsConstructor
public class MyCommandLineRunner implements CommandLineRunner {

    private final StringRedisTemplate stringRedisTemplate;

    @Override
    public void run(String... args) throws Exception {
        // 此处模拟需要预热的数据,可以从其他处获取或者读取数据库
        List<String> dataList = fetchDataForCache();

        log.info("开始进行 Redis 数据预热----------------");

        // 预热 Redis 缓存
        for (int i = 0; i < dataList.size(); i++) {
            stringRedisTemplate.opsForValue().set("key" + i, dataList.get(i));
        }
        log.info("Redis 数据预热完毕----------------");
    }

    private List<String> fetchDataForCache() {
        // 实现获取数据的方法
        // 这里只是示例,返回一个简单的列表
        return Arrays.asList("data1", "data2", "data3");
    }
}

image-20240606203343892

image-20240606203329479

3. CommandLineRunner的其余用法

参考:https://juejin.cn/post/7304635710694457395

4. 其他方法实现数据预热

在 Spring Boot 启动之后,可以通过以下手段实现缓存预热:

  1. 使用启动监听事件实现缓存预热。
  2. 使用 @PostConstruct 注解实现缓存预热。
  3. 使用 CommandLineRunner 或 ApplicationRunner 实现缓存预热。
  4. 通过实现 InitializingBean 接口,并重写 afterPropertiesSet 方法实现缓存预热

4.1 启动监听事件

可以使用 ApplicationListener 监听 ContextRefreshedEvent 或 ApplicationReadyEvent 等应用上下文初始化完成事件,在这些事件触发后执行数据加载到缓存的操作,具体实现如下:

@Component
public class CacheWarmer implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        // 执行缓存预热业务...
        cacheManager.put("key", dataList);
    }
}

或监听 ApplicationReadyEvent 事件,如下代码所示:

@Component
public class CacheWarmer implements ApplicationListener<ApplicationReadyEvent> {
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        // 执行缓存预热业务...
        cacheManager.put("key", dataList);
    }
}

4.2 @PostConstruct 注解

在需要进行缓存预热的类上添加 @Component 注解,并在其方法中添加 @PostConstruct 注解和缓存预热的业务逻辑,具体实现代码如下:

@Component
public class CachePreloader {
    
    @Autowired
    private YourCacheManager cacheManager;

    @PostConstruct
    public void preloadCache() {
        // 执行缓存预热业务...
        cacheManager.put("key", dataList);
    }
}

4.3 CommandLineRunner或ApplicationRunner

CommandLineRunner 和 ApplicationRunner 都是 Spring Boot 应用程序启动后要执行的接口,它们都允许我们在应用启动后执行一些自定义的初始化逻辑,例如缓存预热。

ApplicationRunner 实现示例如下:

@Component
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 执行缓存预热业务...
        // 存入redis
    }
}

CommandLineRunner 和 ApplicationRunner 区别如下:

  1. 方法签名不同
    • CommandLineRunner 接口有一个 run(String... args) 方法,它接收命令行参数作为可变长度字符串数组
    • ApplicationRunner 接口则提供了一个 run(ApplicationArguments args) 方法,它接收一个 ApplicationArguments 对象作为参数,这个对象提供了对传入的所有命令行参数(包括选项和非选项参数)的访问
  2. 参数解析方式不同
    • CommandLineRunner 接口更简单直接,适合处理简单的命令行参数
    • ApplicationRunner 接口提供了一种更强大的参数解析能力,可以通过 ApplicationArguments 获取详细的参数信息,比如获取选项参数及其值、非选项参数列表以及查询是否存在特定参数等
  3. 使用场景不同
    • 当只需要处理一组简单的命令行参数时,可以使用 CommandLineRunner
    • 对于需要精细控制和解析命令行参数的复杂场景,推荐使用 ApplicationRunner

4.4 实现InitializingBean接口

实现 InitializingBean 接口并重写 afterPropertiesSet 方法,可以在 Spring Bean 初始化完成后执行缓存预热,具体实现代码如下:

@Component
public class CachePreloader implements InitializingBean {
    @Autowired
    private YourCacheManager cacheManager;
    @Override
    public void afterPropertiesSet() throws Exception {
        // 执行缓存预热业务...
        // 存入redis
    }
}

5. 参考补充

5.1 免费的Redis服务

https://redislabs.com/redis-cloud

image-20240606202913667

对于临时测试Demo足够了

5.2 spring-boot-starter-data-redis和spring-data-redis依赖

spring-boot-starter-data-redis

  • 作用spring-boot-starter-data-redis 是一个 Spring Boot 启动器(starter),它用于简化 Spring Boot 项目中 Redis 的集成和配置
  • 依赖性:它不仅包括 spring-data-redis,还包括与 Redis 相关的所有必要依赖(例如连接池、Lettuce 或 Jedis 等 Redis 客户端库)
  • 自动配置:当你在 Spring Boot 项目中引入 spring-boot-starter-data-redis 依赖时,Spring Boot 会自动配置 Redis 相关的 Bean(例如 RedisTemplate、连接工厂等),并且可以通过简单的配置文件来定制化设置
  • 推荐使用场景:如果你正在使用 Spring Boot,并希望利用 Spring Boot 的自动配置功能来简化 Redis 的配置和使用,那么应该使用 spring-boot-starter-data-redis
//直接使用
private final StringRedisTemplate stringRedisTemplate;

spring-data-redis

  • 作用spring-data-redis 是 Spring Data 项目的一部分,它提供了对 Redis 的低级别访问功能和操作支持。它不包含自动配置,需要手动配置 Redis 相关的 Bean
  • 依赖性spring-data-redis 只提供核心的 Redis 操作功能,它不会包含具体的 Redis 客户端实现。你需要手动添加所需的客户端库(如 Lettuce 或 Jedis)
  • 灵活性:它提供了更多自定义配置的灵活性,适用于那些需要手动配置或不使用 Spring Boot 的项目
  • 推荐使用场景:如果你不使用 Spring Boot,或者需要对 Redis 配置进行更细粒度的控制,那么应该使用 spring-data-redis

5.3 gitee的demo仓库

https://gitee.com/ucascyl/redis-preheating