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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 11:47:07