第一次使用缓存,因为没预热,翻车了

△Hollis, 一个对Coding有着独特追求的人△

这是Hollis的第 437 篇原创分享
作者 l Hollis
来源 l Hollis(ID:hollischuang)


预热的必要性


预热的方法


Redis预热


应用启动时预热

ApplicationReadyEvent

@EventListener(ApplicationReadyEvent.class)
public void preloadCache() {
   // 在应用启动后执行缓存预热逻辑
   // ...
}


Runner

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

@Component
public class MyCommandLineRunner implements CommandLineRunner {

   @Override
   public void run(String... args) throws Exception {
       // 在应用启动后执行缓存预热逻辑
       // ...
   }
}


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

@Component
public class MyApplicationRunner implements ApplicationRunner {

   @Override
   public void run(ApplicationArguments args) throws Exception {
       // 在应用启动后执行缓存预热逻辑
       // ...
   }

}

private void callRunners(ApplicationContext context, ApplicationArguments args) {
   List runners = new ArrayList<>();
   runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
   runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
   AnnotationAwareOrderComparator.sort(runners);
   for (Object runner : new LinkedHashSet<>(runners)) {
       if (runner instanceof ApplicationRunner) {
           callRunner((ApplicationRunner) runner, args);
       }
       if (runner instanceof CommandLineRunner) {
           callRunner((CommandLineRunner) runner, args);
       }
   }
}


使用InitializingBean接口

import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

@Component
public class CachePreloader implements InitializingBean {

   @Override
   public void afterPropertiesSet() throws Exception {
       // 执行缓存预热逻辑
       // ...
   }
}

使用@PostConstruct注解

import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;

@Component
public class CachePreloader {

   @PostConstruct
   public void preloadCache() {
       // 执行缓存预热逻辑
       // ...
   }
}



定时任务预热

@Scheduled(cron = "0 0 1 * * ?") // 每天凌晨1点执行
public void scheduledCachePreload() {
   // 执行缓存预热逻辑
   // ...
}



缓存器预热

import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class MyCacheService {

   private final LoadingCache cache;

   public MyCacheService() {
       this.cache = Caffeine.newBuilder()
               .refreshAfterWrite(1, TimeUnit.MINUTES)  // 配置自动刷新,1分钟刷新一次
               .build(key -> loadDataFromSource(key));  // 使用加载器加载数据
   }

   public String getValue(String key) {
       return cache.get(key);
   }

   private String loadDataFromSource(String key) {
       // 从数据源加载数据的逻辑
       // 这里只是一个示例,实际应用中可能是从数据库、外部服务等获取数据
       System.out.println("Loading data for key: " + key);
       return "Value for " + key;
   }
}