You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中基于@PostConstruct的缓存如何实现定期自动刷新?

原生Java/Spring实现缓存定期自动刷新方案

针对你的场景,以下两种基于原生Java/Spring类库的方案可以实现缓存的定期自动刷新,无需依赖第三方缓存框架:

方案一:使用Spring @Scheduled注解(推荐,贴合Spring生态)

这是Spring原生支持的定时任务方案,配置简单,无需额外依赖。

实现步骤:

  1. 在Spring Boot启动类或配置类上添加@EnableScheduling,开启定时任务功能:
@SpringBootApplication
@EnableScheduling
public class YourApplication {
    public static void main(String[] args) {
        SpringApplication.run(YourApplication.class, args);
    }
}
  1. 重构缓存类,将初始化逻辑抽为公共刷新方法,通过@PostConstruct初始化缓存,同时用@Scheduled配置定时刷新:
@Component
public class ConfigCache {

    private final MyRepository myRepository;
    // volatile保证多线程下缓存替换的可见性
    private volatile ConcurrentHashMap<String, String> cacheMap = new ConcurrentHashMap<>();

    // 构造注入Repository
    public ConfigCache(MyRepository myRepository) {
        this.myRepository = myRepository;
    }

    @PostConstruct
    public void initCache() {
        refreshCache();
    }

    // 每30分钟刷新一次(cron表达式:0秒、每30分钟、任意小时/日期/月份/星期)
    @Scheduled(cron = "0 0/30 * * * ?")
    public void refreshCache() {
        // 先加载全量数据到临时Map,避免刷新过程中缓存不一致
        ConcurrentHashMap<String, String> newCache = new ConcurrentHashMap<>();
        List<MyEntity> configList = myRepository.findAll();
        for (MyEntity entity : configList) {
            newCache.put(entity.getKey(), entity.getValue());
        }
        // 原子替换缓存Map,保证线程安全
        this.cacheMap = newCache;
    }

    // 对外提供的缓存查询方法
    public String getConfig(String key) {
        return cacheMap.get(key);
    }
}

方案二:使用Java原生ScheduledExecutorService(纯Java实现,不依赖Spring定时注解)

如果不想依赖Spring的定时注解,可以用Java自带的线程池调度器实现定时任务。

@Component
public class ConfigCache {

    private final MyRepository myRepository;
    private volatile ConcurrentHashMap<String, String> cacheMap = new ConcurrentHashMap<>();
    private ScheduledExecutorService scheduler;

    public ConfigCache(MyRepository myRepository) {
        this.myRepository = myRepository;
    }

    @PostConstruct
    public void initCache() {
        refreshCache();
        // 初始化单线程调度器,首次延迟30分钟,之后每30分钟执行一次刷新
        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(this::refreshCache, 30, 30, TimeUnit.MINUTES);
    }

    // 应用关闭时销毁调度器,避免资源泄漏
    @PreDestroy
    public void shutdownScheduler() {
        if (scheduler != null) {
            scheduler.shutdown();
            try {
                if (!scheduler.awaitTermination(1, TimeUnit.MINUTES)) {
                    scheduler.shutdownNow();
                }
            } catch (InterruptedException e) {
                scheduler.shutdownNow();
            }
        }
    }

    private void refreshCache() {
        ConcurrentHashMap<String, String> newCache = new ConcurrentHashMap<>();
        List<MyEntity> configList = myRepository.findAll();
        for (MyEntity entity : configList) {
            newCache.put(entity.getKey(), entity.getValue());
        }
        this.cacheMap = newCache;
    }

    public String getConfig(String key) {
        return cacheMap.get(key);
    }
}

关键注意事项

  • 线程安全:用volatile修饰缓存Map,保证多线程下的可见性;刷新时先加载数据到临时Map再替换原Map,避免部分更新导致的缓存不一致。
  • 性能优化:如果数据库配置数据量较大,建议分批查询加载,避免单次查询耗时过长阻塞应用。
  • 异常处理:可以在refreshCache方法中添加异常捕获与日志记录,必要时实现重试逻辑,避免单次刷新失败导致缓存长期失效。
  • 任务调度线程:使用@Scheduled时,默认是单线程调度,若存在多个定时任务,可配置TaskScheduler使用线程池,防止任务阻塞。

内容的提问来源于stack exchange,提问作者Pranjal Sharma

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 12:05:29