本文目录导读:

我来为您提供一个完整的Java缓存预热案例,包含多种实现方案。
基础缓存预热架构
1 缓存接口定义
public interface CacheService<K, V> {
V get(K key);
void put(K key, V value);
void clear();
boolean isPreheated();
}
2 本地缓存实现
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
public class LocalCacheService<K, V> implements CacheService<K, V> {
private final ConcurrentHashMap<K, V> cache = new ConcurrentHashMap<>();
private final AtomicBoolean preheated = new AtomicBoolean(false);
@Override
public V get(K key) {
return cache.get(key);
}
@Override
public void put(K key, V value) {
cache.put(key, value);
}
@Override
public void clear() {
cache.clear();
preheated.set(false);
}
@Override
public boolean isPreheated() {
return preheated.get();
}
public void setPreheated(boolean preheated) {
this.preheated.set(preheated);
}
}
Spring Boot 缓存预热方案
1 数据模型
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class Product {
private Long id;
private String name;
private Double price;
private Integer stock;
private String category;
private LocalDateTime createTime;
}
2 数据源模拟
import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Repository
public class ProductRepository {
private final Map<Long, Product> database = new ConcurrentHashMap<>();
@PostConstruct
public void init() {
// 模拟数据库数据
for (long i = 1; i <= 10000; i++) {
Product product = new Product();
product.setId(i);
product.setName("Product-" + i);
product.setPrice(100.0 + i);
product.setStock(100);
product.setCategory("Category-" + (i % 10));
product.setCreateTime(LocalDateTime.now());
database.put(i, product);
}
}
public Product findById(Long id) {
// 模拟数据库查询延迟
try {
Thread.sleep(10);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return database.get(id);
}
public List<Product> findAll() {
return new ArrayList<>(database.values());
}
}
3 缓存预热服务
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
@Service
public class CacheWarmUpService {
@Autowired
private ProductRepository productRepository;
@Autowired
private LocalCacheService<Long, Product> productCache;
// 预热线程池
private final ExecutorService warmUpExecutor = Executors.newFixedThreadPool(10);
// 预热进度
private final AtomicInteger progress = new AtomicInteger(0);
@PostConstruct
public void initialize() {
if (!productCache.isPreheated()) {
warmUpCache();
}
}
/**
* 全量缓存预热
*/
public void warmUpCache() {
log.info("开始缓存预热...");
long startTime = System.currentTimeMillis();
List<Product> allProducts = productRepository.findAll();
int totalSize = allProducts.size();
// 使用CountDownLatch等待所有预热任务完成
CountDownLatch latch = new CountDownLatch(totalSize);
allProducts.forEach(product -> {
warmUpExecutor.submit(() -> {
try {
// 执行预热
productCache.put(product.getId(), product);
progress.incrementAndGet();
} finally {
latch.countDown();
}
});
});
try {
// 等待所有任务完成,设置超时时间
boolean completed = latch.await(5, TimeUnit.MINUTES);
if (completed) {
productCache.setPreheated(true);
long endTime = System.currentTimeMillis();
log.info("缓存预热完成,共加载{}条数据,耗时:{}ms", totalSize, (endTime - startTime));
} else {
log.error("缓存预热超时");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("缓存预热被中断", e);
}
}
/**
* 获取预热进度
*/
public double getProgress() {
return (double) progress.get() / productRepository.findAll().size() * 100;
}
/**
* 检查缓存状态
*/
public boolean isCacheReady() {
return productCache.isPreheated();
}
}
分层预热策略
1 热门数据优先预热
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class SmartCacheWarmUpService {
@Autowired
private ProductRepository productRepository;
@Autowired
private LocalCacheService<Long, Product> productCache;
// 热门商品ID(可以从历史数据中获取)
private final List<Long> hotProductIds = Arrays.asList(1L, 2L, 3L, 4L, 5L, 100L, 200L, 500L);
/**
* 分层预热
* 第一层:热门数据
* 第二层:常规数据
* 第三层:冷门数据
*/
public void tieredWarmUp() {
log.info("开始分层缓存预热...");
// 第一层:预热热门数据(立即执行)
warmUpHotData();
// 第二层:预热常规数据(延迟执行)
scheduleWarmUpNormalData(1000); // 延迟1秒
// 第三层:预热冷门数据(后台执行)
scheduleWarmUpColdData(5000); // 延迟5秒
}
private void warmUpHotData() {
hotProductIds.parallelStream().forEach(id -> {
Product product = productRepository.findById(id);
if (product != null) {
productCache.put(id, product);
log.debug("热门商品缓存预热:{}", id);
}
});
log.info("热门数据预热完成");
}
private void scheduleWarmUpNormalData(long delayMs) {
new Timer().schedule(new TimerTask() {
@Override
public void run() {
// 预热访问频率较高的数据
productRepository.findAll().stream()
.filter(p -> !hotProductIds.contains(p.getId()))
.limit(1000) // 预热前1000条常规数据
.forEach(p -> productCache.put(p.getId(), p));
log.info("常规数据预热完成");
}
}, delayMs);
}
private void scheduleWarmUpColdData(long delayMs) {
new Timer().schedule(new TimerTask() {
@Override
public void run() {
// 后台预热剩余数据
CompletableFuture.runAsync(() -> {
productRepository.findAll().stream()
.filter(p -> productCache.get(p.getId()) == null)
.forEach(p -> productCache.put(p.getId(), p));
log.info("冷数据预热完成");
});
}
}, delayMs);
}
}
健康检查与监控
1 缓存健康检查
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.concurrent.atomic.AtomicLong;
@Component
public class CacheHealthChecker {
@Autowired
private LocalCacheService<Long, Product> productCache;
@Autowired
private ProductRepository productRepository;
private final AtomicLong cacheHitCount = new AtomicLong(0);
private final AtomicLong cacheMissCount = new AtomicLong(0);
/**
* 定时检测缓存命中率
*/
@Scheduled(fixedRate = 60000) // 每分钟检测一次
public void checkCacheHealth() {
if (!productCache.isPreheated()) {
log.warn("缓存尚未预热完成");
return;
}
// 随机抽样检测
long testCount = 100;
long hitCount = 0;
for (int i = 0; i < testCount; i++) {
Long randomId = ThreadLocalRandom.current().nextLong(1, 10001);
Product cachedProduct = productCache.get(randomId);
Product dbProduct = productRepository.findById(randomId);
if (cachedProduct != null && cachedProduct.equals(dbProduct)) {
hitCount++;
}
}
double hitRate = (double) hitCount / testCount;
if (hitRate < 0.95) {
log.warn("缓存命中率异常:{}%,需要重新预热", hitRate * 100);
// 触发重新预热
triggerReWarmUp();
} else {
log.info("缓存健康状态良好,命中率:{}%", hitRate * 100);
}
}
private void triggerReWarmUp() {
productCache.clear();
// 执行重新预热逻辑
}
}
启动时自动预热
1 配置类
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "cache.warmup")
public class CacheWarmUpConfig {
private boolean enabled = true;
private int threadPoolSize = 10;
private long timeoutMinutes = 5;
private String strategy = "full"; // full, tiered, hot_only
// getters and setters
}
2 启动监听器
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class CacheWarmUpListener implements ApplicationListener<ApplicationReadyEvent> {
@Autowired
private CacheWarmUpService warmUpService;
@Autowired
private SmartCacheWarmUpService smartWarmUpService;
@Autowired
private CacheWarmUpConfig warmUpConfig;
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
if (!warmUpConfig.isEnabled()) {
log.info("缓存预热已禁用");
return;
}
log.info("应用程序已启动,开始执行缓存预热...");
// 根据配置选择预热策略
switch (warmUpConfig.getStrategy()) {
case "full":
warmUpService.warmUpCache();
break;
case "tiered":
smartWarmUpService.tieredWarmUp();
break;
case "hot_only":
smartWarmUpService.warmUpHotData();
break;
default:
warmUpService.warmUpCache();
}
}
}
使用示例
1 application.yml配置
cache:
warmup:
enabled: true
thread-pool-size: 10
timeout-minutes: 5
strategy: tiered
2 业务使用示例
@Service
public class ProductService {
@Autowired
private LocalCacheService<Long, Product> productCache;
@Autowired
private ProductRepository productRepository;
public Product getProductById(Long id) {
// 从缓存获取
Product cachedProduct = productCache.get(id);
if (cachedProduct != null) {
return cachedProduct;
}
// 缓存未命中,从数据库加载
Product dbProduct = productRepository.findById(id);
if (dbProduct != null) {
productCache.put(id, dbProduct);
}
return dbProduct;
}
}
3 REST API监控
@RestController
@RequestMapping("/api/cache")
public class CacheController {
@Autowired
private CacheWarmUpService warmUpService;
@GetMapping("/status")
public ResponseEntity<Map<String, Object>> getCacheStatus() {
Map<String, Object> status = new HashMap<>();
status.put("preheated", warmUpService.isCacheReady());
status.put("progress", warmUpService.getProgress());
return ResponseEntity.ok(status);
}
@PostMapping("/warmup")
public ResponseEntity<String> triggerWarmUp() {
CompletableFuture.runAsync(() -> warmUpService.warmUpCache());
return ResponseEntity.accepted().body("缓存预热已启动");
}
}
这个缓存预热方案包含了:
- 多种预热策略:全量预热、分层预热、热点优先
- 并发控制:使用线程池和CountDownLatch
- 健康监控:定时检查缓存命中率
- 失败处理:超时机制和重试逻辑
- 配置灵活:通过配置文件控制预热行为
- 启动自动执行:利用Spring事件机制
你可以根据实际业务需求选择合适的预热策略,并调整线程池大小、超时时间等参数。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播