news 2026/5/1 1:45:47

[004][缓存模块]Caffeine缓存自定义:构建灵活的Spring Boot缓存管理器

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
[004][缓存模块]Caffeine缓存自定义:构建灵活的Spring Boot缓存管理器

[004][缓存模块]Caffeine缓存自定义:构建灵活的Spring Boot缓存管理器

本项目代码:https://gitee.com/yunjiao-source/tutorials4j/tree/master/framework

在Spring Boot应用中,缓存是提升系统性能的重要手段。Caffeine作为高性能的本地缓存库,常与Spring的CacheManager抽象整合使用。然而,默认的CaffeineCacheManager仅支持全局统一的缓存配置(如过期时间、最大容量等),无法针对不同业务缓存进行差异化定制。本文将通过分析一个自定义的Caffeine缓存模块,展示如何实现支持“每个缓存独立配置”的灵活缓存管理器。

一、背景与目标

1.1 痛点

  • 业务缓存需求各异:用户会话缓存需要较短过期时间,商品目录缓存可设置较长过期时间且需要自动刷新。
  • 默认CaffeineCacheManager的配置是全局的,若想差异化,只能创建多个CacheManager实例,管理复杂。

1.2 设计目标

  • 支持全局默认配置 + 每个缓存名称可覆盖配置。
  • 复用Spring的CaffeineCacheManager,尽量减少侵入。
  • 提供线程安全的缓存管理器创建器,支持延迟初始化。
  • 保持与Spring Boot自动配置的无缝集成。

二、模块功能解析

项目提供了四个核心类,分别负责配置加载、工具方法、缓存管理器创建和个性化缓存生成。

2.1CacheCaffeineConfiguration– Spring配置装配

@Configuration(proxyBeanMethods=false)publicclassCacheCaffeineConfiguration{@BeanCaffeine<Object,Object>caffeine(CacheCaffeinePropertiesproperties){Caffeine<Object,Object>caffeine=Caffeine.newBuilder();CaffeineUtils.copyOption(caffeine,properties);returncaffeine;}@Bean@ConditionalOnMissingBean(CaffeineCacheManagerCreator.class)CaffeineCacheManagerCreatorcaffeineCacheManagerCreator(Caffeine<Object,Object>caffeine,CacheCaffeinePropertiesproperties){returnnewCaffeineCacheManagerCreator(properties,caffeine);}}
  • 作用:声明创建Caffeine实例的Bean,并通过CaffeineUtils将全局属性(如initialCapacitymaximumSize等)复制到构建器中。然后创建CaffeineCacheManagerCreator,它作为工厂负责生成最终的CacheManager
  • 亮点:使用@ConditionalOnMissingBean允许用户覆盖默认的创建器实现,提供扩展点。

2.2CaffeineUtils– 配置复制工具

publicinterfaceCaffeineUtils{staticvoidcopyOption(Caffeine<Object,Object>caffeine,CaffeineOptionsoptions){caffeine.initialCapacity(options.getInitialCapacity()).maximumSize(options.getMaximumSize());if(options.getExpireAfterAccess()!=null){caffeine.expireAfterAccess(options.getExpireAfterAccess());}// ... 其他可选配置if(Objects.equals(Boolean.TRUE,options.getRecordStats())){caffeine.recordStats();}}}
  • 作用:将CaffeineOptions(包含过期策略、刷新间隔、统计开关等)批量设置到Caffeine构建器中。
  • 设计:声明为接口静态方法,便于复用;判空处理支持可选配置。

2.3CaffeineCacheManagerCreator– 线程安全的单例创建器

publicclassCaffeineCacheManagerCreatorimplementsSupplier<CaffeineCacheManager>{privatefinalCacheCaffeinePropertiesproperties;privatefinalCaffeine<Object,Object>caffeine;privatevolatileCaffeineCacheManagerinstance;@OverridepublicCaffeineCacheManagerget(){if(instance!=null)returninstance;synchronized(this){if(instance!=null)returninstance;instance=newInstance();}returninstance;}publicCaffeineCacheManagernewInstance(){FlexibleCaffeineCacheManagermanager=newFlexibleCaffeineCacheManager(properties);manager.setCaffeine(caffeine);returnmanager;}}
  • 作用:实现Supplier接口,提供单例的CaffeineCacheManager。使用DCL(双重检查锁)保证线程安全,同时避免每次获取都创建新实例。
  • 优势:延迟加载,仅在首次调用get()时才真正构建缓存管理器;可作为Spring Bean直接注入,也可在需要时手动获取。

2.4FlexibleCaffeineCacheManager– 核心个性化逻辑

publicclassFlexibleCaffeineCacheManagerextendsCaffeineCacheManager{privatefinalCacheCaffeinePropertiesproperties;@OverrideprotectedCache<Object,Object>createNativeCaffeineCache(Stringname){Map<String,CaffeineOptions>optionsMap=properties.getNamedCaches();if(MapUtils.isNotEmpty(optionsMap)&&optionsMap.containsKey(name)){CaffeineOptionscaffeineOptions=optionsMap.get(name);caffeineOptions.mergeNullValue(properties);// 未设置的项回填全局值Caffeine<Object,Object>caffeine=Caffeine.newBuilder();CaffeineUtils.copyOption(caffeine,caffeineOptions);log.debug("初始化缓存: {}",name);returncaffeine.build();}returnsuper.createNativeCaffeineCache(name);}}
  • 关键重写createNativeCaffeineCache(String name)CaffeineCacheManager中每个缓存创建时调用的方法。我们覆盖它,根据缓存名称从properties.getNamedCaches()中查找专属配置。
  • 配置合并caffeineOptions.mergeNullValue(properties)将未显式设置的属性(如expireAfterWrite为null)继承自全局配置,避免遗漏。
  • 降级处理:若没有专属配置,则调用父类方法,父类会使用默认的Caffeine实例(即全局配置)来构建缓存。

三、自定义扩展的设计精髓

3.1 属性模型设计

假设CacheCaffeineProperties包含:

  • 全局配置:initialCapacitymaximumSizeexpireAfterWrite等。
  • Map<String, CaffeineOptions> namedCaches:key为缓存名称,value为该缓存的个性化配置。

CaffeineOptions中定义与全局配置相同的字段,并提供一个mergeNullValue方法:对于自身为null的属性,从传入的默认配置中取值。

3.2 为什么需要CaffeineCacheManagerCreator

直接暴露FlexibleCaffeineCacheManager作为Bean也可以,但创建器的好处:

  1. 单例控制:确保整个应用只有一个CacheManager实例(Spring默认也如此,但通过Supplier可更明确控制创建时机)。
  2. 延迟初始化:避免在Spring容器启动阶段过早构建缓存(尤其是在缓存配置依赖外部动态参数时)。
  3. 测试友好:可mock或替换创建逻辑。

3.3 线程安全与性能

CaffeineCacheManager本身是线程安全的,但createNativeCaffeineCache会被多次调用(每个缓存名称调用一次)。FlexibleCaffeineCacheManager中每次有专属配置时都会新建一个Caffeine实例,这符合预期——不同缓存本就应拥有独立的配置和缓存实例。而CaffeineCacheManagerCreator中的DCL确保全局只有一个管理实例,避免了重复创建管理器的开销。

四、使用示例与配置

4.1 配置文件(application.yml)

tutorials4j:cache:caffeine:allow-null-values:falseinitial-capacity:16maximum-size:1000expire-after-write:60srecord-stats:truenamed-caches:users:expire-after-write:30smaximum-size:500products:expire-after-access:10mrefresh-after-write:5m
  • 全局:默认写入后60秒过期,最大1000条。
  • users缓存:写入后30秒过期,最大500条(覆盖全局过期和最大容量)。
  • products缓存:访问后10分钟过期,写入后5分钟刷新(注意refreshAfterWrite需要搭配CacheLoader,此处仅为示例)。

4.2 启用缓存

@Configuration@EnableCachingpublicclassMyCacheConfig{@BeanpublicCacheManagercacheManager(CaffeineCacheManagerCreatorcreator){returncreator.get();// 获取单例缓存管理器}}

或者在自动配置中直接使用CacheCaffeineConfiguration,它会自动装配创建器并暴露CacheManager

4.3 业务使用

@ServicepublicclassProductService{@Cacheable("products")publicProductgetProduct(Longid){...}@CacheEvict(cacheNames="users",key="#userId")publicvoidevictUser(StringuserId){...}}

此时products缓存将应用5分钟刷新+10分钟访问过期策略,而users缓存则使用30秒写入过期。

五、总结

通过上述设计,我们实现了:

  • 细粒度配置:每个缓存名称可定义独立的过期、容量等参数。
  • 线程安全且高效:单例管理器 + DCL,避免重复构造。
  • 易扩展:通过@ConditionalOnMissingBean允许用户替换创建器或缓存管理器。
  • 兼容Spring标准:继承CaffeineCacheManager,所有Spring缓存注解(@Cacheable等)无需改动。

Caffeine作为“现代Java本地缓存之王”,配合灵活的缓存管理器,能让你的应用在性能和业务需求之间取得完美平衡。希望本文的自定义实现能为你的项目提供有益的参考。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 1:39:35

有机溶剂回收设备厂家:行业现状、技术路径与选型指南

随着化工、制药、电子等行业环保要求趋严&#xff0c;有机溶剂回收设备成为企业降本增效、合规排放的核心装备。行业报告显示&#xff0c;2025 年国内有机溶剂回收设备市场规模突破 80 亿元&#xff0c;年复合增长率超 15%&#xff0c;但市场供给端呈现 “量多质不均” 的格局&…

作者头像 李华
网站建设 2026/5/1 1:39:10

2025届最火的十大降AI率神器实测分析

Ai论文网站排名&#xff08;开题报告、文献综述、降aigc率、降重综合对比&#xff09; TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 核心策略是降低文章被识别成 AIGC 生成内容&#xff0c;其在于消解机器生成的规律性特征。其…

作者头像 李华
网站建设 2026/5/1 1:31:22

【Linux网络】进程间关系与守护进程

1. 进程组1.1 什么是进程组之前我们提到了进程的概念&#xff0c; 其实每一个进程除了有一个进程ID(PID)之外&#xff0c;还属于一个进程组。进程组是一个或者多个进程的集合&#xff0c;一个进程组可以包含多个进程。 每一个进程组也有一个唯一的进程组ID(PGID)&#xff0c; 并…

作者头像 李华