Spring Boot整合Caffeine缓存:自定义过期逻辑的类型兼容问题
解决方案
方案1:针对特定缓存名定制Caffeine实例(推荐)
Spring的CaffeineCacheManager允许通过覆盖createCaffeineCache方法,为不同缓存名创建独立的、类型安全的Caffeine配置。无需全局设置Caffeine<Object, Object>,精准控制目标缓存的规则:
@Configuration public class CacheConfig { @Bean public CacheManager jobCacheManager() { return new CaffeineCacheManager("jobCache") { @Override protected Caffeine<Object, Object> createCaffeineCache(String name) { if ("jobCache".equals(name)) { return Caffeine.newBuilder() .expireAfter(new JobExpiry()) .build(); } return super.createCaffeineCache(name); } }; } // 完全类型安全的自定义Expiry,无强制转换 private static class JobExpiry implements Expiry<UUID, Job> { @Override public long expireAfterCreate(UUID key, Job job, long currentTime) { return job.getStatus() == Job.Status.READY ? TimeUnit.DAYS.toNanos(3) : TimeUnit.HOURS.toNanos(1); } @Override public long expireAfterUpdate(UUID key, Job job, long currentTime, long currentDuration) { return switch (job.getStatus()) { case RUNNING -> TimeUnit.HOURS.toNanos(2); case COMPLETED -> TimeUnit.MINUTES.toNanos(30); default -> currentDuration; }; } @Override public long expireAfterRead(UUID key, Job job, long currentTime, long currentDuration) { return job.getStatus() == Job.Status.READY ? TimeUnit.DAYS.toNanos(3) : currentDuration; } } }
使用时直接注入CacheManager并获取"jobCache",操作全程保持UUID和Job的类型安全。
方案2:利用泛型通配符兼容类型
如果需要全局复用Caffeine配置,可将Bean声明为Caffeine<? super UUID, ? extends Job>,它能安全向上转型为Caffeine<Object, Object>,同时保证Expiry的类型安全:
@Configuration public class CacheConfig { @Bean public Caffeine<? super UUID, ? extends Job> jobCaffeine() { return Caffeine.newBuilder() .expireAfter(new JobExpiry()); } @Bean public CacheManager cacheManager(Caffeine<? super UUID, ? extends Job> jobCaffeine) { CaffeineCacheManager cacheManager = new CaffeineCacheManager(); // 通配符泛型的上下界保证了转换的安全性 cacheManager.setCaffeine((Caffeine<Object, Object>) jobCaffeine); return cacheManager; } private static class JobExpiry implements Expiry<UUID, Job> { // 同方案1的Expiry实现 } }
仅在设置CacheManager时做一次安全泛型转换,避免在Expiry中处理类型强制转换。
方案3:自定义类型安全的CacheManager
若想彻底规避泛型转换,可直接实现CacheManager接口,管理特定类型的Caffeine缓存:
@Configuration public class JobCacheConfig { @Bean public Cache<UUID, Job> jobCache() { return Caffeine.newBuilder() .expireAfter(new JobExpiry()) .build(); } @Bean public CacheManager jobCacheManager(Cache<UUID, Job> jobCache) { return new CacheManager() { @Override public Cache getCache(String name) { return "jobCache".equals(name) ? jobCache : null; } @Override public Collection<String> getCacheNames() { return Collections.singleton("jobCache"); } }; } private static class JobExpiry implements Expiry<UUID, Job> { // 同方案1的Expiry实现 } }
使用时直接注入Cache<UUID, Job>或通过CacheManager获取,全程无强制转换,类型安全。
内容的提问来源于stack exchange,提问作者Jakub Łaba
相关产品推荐
相关产品推荐

