导读:本期聚焦于小伙伴创作的《Java项目如何实现应用启动时的缓存预热?CommandLineRunner与ApplicationRunner实战》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Java项目如何实现应用启动时的缓存预热?CommandLineRunner与ApplicationRunner实战》有用,将其分享出去将是对创作者最好的鼓励。

在Java Spring Boot项目开发中,应用启动后的首次请求往往因为缓存未初始化,需要查询数据库加载数据,导致响应时间较长。缓存预热就是解决这个问题的重要手段,而CommandLineRunner和ApplicationRunner是Spring Boot提供的用于实现启动后执行逻辑的回调接口,非常适合用来实现缓存预热功能。

Java项目如何实现应用启动时的缓存预热?CommandLineRunner与ApplicationRunner实战

什么是缓存预热

缓存预热指的是在应用启动阶段,提前将预期会被频繁访问的热点数据从数据库、文件系统等持久化存储中加载到缓存(如Redis、Caffeine等)中,当用户发起请求时可以直接从缓存获取数据,不需要再去查询底层存储,从而提升响应速度,减少数据库压力。

CommandLineRunner接口介绍

CommandLineRunner是Spring Boot提供的一个函数式接口,只有一个run(String... args)方法,该方法会在Spring容器完全初始化完成后执行,方法的参数是应用启动时传入的命令行参数。

基本使用示例

实现CommandLineRunner接口,重写run方法,在方法中编写缓存预热的逻辑:

import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class CachePreheatRunner implements CommandLineRunner {

    // 模拟缓存组件,实际项目中可替换为RedisTemplate、CaffeineCache等
    private Map<String, Object> cache = new HashMap<>();

    @Override
    public void run(String... args) throws Exception {
        System.out.println("开始执行缓存预热逻辑");
        // 模拟从数据库查询热点数据
        List<String> hotDataList = queryHotDataFromDb();
        for (String data : hotDataList) {
            cache.put(data, "data_" + data);
        }
        System.out.println("缓存预热完成,当前缓存数据量:" + cache.size());
    }

    // 模拟数据库查询方法
    private List<String> queryHotDataFromDb() {
        List<String> list = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            list.add("hot_key_" + i);
        }
        return list;
    }
}

执行顺序控制

如果有多个类实现了CommandLineRunner接口,可以通过@Order注解或者实现Ordered接口来指定执行顺序,数值越小越先执行:

import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Order(1)
public class FirstPreheatRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("第一个缓存预热任务执行");
    }
}

@Component
@Order(2)
public class SecondPreheatRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("第二个缓存预热任务执行");
    }
}

ApplicationRunner接口介绍

ApplicationRunner和CommandLineRunner功能类似,也是Spring容器初始化完成后执行的回调接口,区别在于它的run方法参数是ApplicationArguments对象,该对象对命令行参数做了更友好的封装,可以方便获取带key的参数和不带key的参数。

基本使用示例

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
public class AppCachePreheatRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("ApplicationRunner执行缓存预热");
        // 获取命令行参数,例如启动时传入 --env=test
        List<String> envList = args.getOptionValues("env");
        if (envList != null && !envList.isEmpty()) {
            System.out.println("当前环境:" + envList.get(0));
        }
        // 执行缓存加载逻辑
        loadHotDataToCache();
    }

    private void loadHotDataToCache() {
        // 实际缓存加载逻辑,此处省略
        System.out.println("热点数据加载到缓存完成");
    }
}

CommandLineRunner与ApplicationRunner的区别

两个接口的核心区别如下:

对比项CommandLineRunnerApplicationRunner
run方法参数String数组,直接接收原始命令行参数ApplicationArguments对象,封装了命令行参数,支持按key获取参数
参数处理难度需要自行解析参数格式提供了getOptionNames、getOptionValues等方法,处理更方便
执行顺序都支持@Order注解控制顺序,相同Order时ApplicationRunner先执行

结合Redis实现完整缓存预热

实际项目中通常会使用Redis作为缓存组件,下面演示结合RedisTemplate实现缓存预热的完整示例:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class RedisCachePreheatRunner implements CommandLineRunner {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public void run(String... args) throws Exception {
        System.out.println("开始执行Redis缓存预热");
        // 模拟查询数据库中的商品热点数据
        List<Product> hotProducts = productMapper.selectHotProducts();
        for (Product product : hotProducts) {
            // 将商品数据存入Redis,key格式为 product:hot:{商品id}
            String key = "product:hot:" + product.getId();
            redisTemplate.opsForValue().set(key, product);
        }
        System.out.println("Redis缓存预热完成,共加载" + hotProducts.size() + "条商品数据");
    }

    // 模拟商品实体类
    static class Product {
        private Long id;
        private String name;
        private BigDecimal price;

        // getter和setter省略
    }

    // 模拟商品Mapper,实际项目中替换为MyBatis或JPA的Mapper
    // @Autowired
    // private ProductMapper productMapper;
    private ProductMapper productMapper;

    interface ProductMapper {
        List<Product> selectHotProducts();
    }
}

注意事项

  • 缓存预热逻辑如果执行时间过长,会延长应用启动的总时间,建议只加载必要的热点数据,避免加载全量数据。
  • 如果预热逻辑中涉及数据库查询,需要注意数据库连接是否已经初始化完成,Spring Boot中CommandLineRunner执行时数据源已经可用,一般不会有问题。
  • 如果预热失败,需要考虑是否要影响应用启动,可通过try-catch包裹逻辑,避免预热异常导致应用启动失败。
  • 多个Runner的执行顺序要合理规划,避免后面的Runner依赖前面的Runner执行结果但顺序错误的情况。

JavaCommandLineRunnerApplicationRunner缓存预热Spring_Boot修改时间:2026-06-22 02:36:25

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。