JetCache 通用缓存访问框架入门与实践:注解方法缓存、两级缓存、自动刷新与 Cache API 全解析

发布时间:2026/10/12 1:55:23
JetCache 通用缓存访问框架入门与实践:注解方法缓存、两级缓存、自动刷新与 Cache API 全解析 后端缓存抽象【免费下载链接】jetcacheJetCache is a Java cache framework.项目地址https://gitcode.com/gh_mirrors/je/jetcache点击查看免费下载导读本文以阿里巴巴开源的通用缓存访问框架 JetCache 为主题围绕其统一 Cache API、声明式方法缓存Cached/CacheUpdate/CacheInvalidate、两级缓存、自动刷新与加载保护、分布式锁、异步 API 等核心能力展开并结合仓库源码讲解底层实现原理。读完本文你将掌握如何用 JetCache 在 Spring 应用中用注解快速接入本地/远程缓存如何用CacheManager与QuickConfig以编程方式创建缓存实例以及如何配置自动刷新、穿透保护与反序列化安全过滤器。JetCache 是阿里巴巴开源的通用缓存访问框架。如果你对 Spring Cache 很熟悉那么值得花一点时间了解一下 JetCache——它更贴近实际生产场景注解原生支持 TTL 与缓存类型选择同时提供了类似 JSR-107 风格的统一Cache接口用起来像 Map 一样简单。一、JetCache 的核心能力一览JetCache 提供的核心能力包括提供统一的、类似 JSR-107 风格的 API 访问 Cache并可通过注解创建并配置 Cache 实例通过注解实现声明式的方法缓存支持 TTL 和两级缓存分布式缓存自动刷新分布式锁2.2分布式多级缓存场景下缓存更新后自动让所有 local cache 失效2.7支持异步 Cache API支持 Spring BootKey 的生成策略和 Value 的序列化策略可定制针对所有 Cache 实例和方法缓存的自动统计。其中统一接口 注解声明 自动刷新 多级缓存失效通知是 JetCache 区别于普通缓存封装库的核心竞争力下文逐一展开。二、快速开始用 Cached 实现声明式方法缓存最简单的使用场景在 Service 接口方法上加一个注解即可public interface UserService { Cached(expire 3600, cacheType CacheType.REMOTE) User getUserById(long userId); }这和 Spring Cache 很像不过Cached注解原生支持了 TTL超时时间。cacheType有LOCAL/REMOTE/BOTH三种选择定义见 CacheType.javacacheType含义适用场景LOCAL本地内存缓存如 Caffeine、LinkedHashMap数据量小、单机即可承载的场景REMOTE远程缓存 Server如 Redis集群共享、跨进程一致的场景BOTH两级缓存本地 远程兼顾响应速度与集群一致性合理使用LOCAL或BOTH类型可以显著降低 Cache Server 的压力同时降低服务响应时间。Cached注解的完整属性定义见 Cached.java常用属性说明属性默认值说明areadefault多缓存后端multi cache area时指定使用哪个缓存区域name自动生成Cache 实例名称用于统计展示以及作为远程缓存的 key 前缀同一 area 下不同注解不要重名enabledtrue是否启用方法缓存置为 false 后可用CacheContext.enableCache(Supplier)在指定线程上下文临时启用expire未定义超时时间未指定时用全局配置仍未指定则为无穷大timeUnitSECONDSexpire 的时间单位localExpire未定义BOTH类型时本地缓存过期时间未设置时与expire一致cacheTypeREMOTELOCAL/REMOTE/BOTHsyncLocalfalseBOTH且远程缓存支持广播时put/remove 后同步失效所有进程的本地缓存localLimit全局配置缺省 100本地缓存最大元素数serialPolicy全局配置缺省java远程缓存的序列化策略内置java/kryo/kryo5keyConvertor全局配置缺省fastjson2Key 转换器方法缓存必须指定key未定义用表达式指定 key不指定时用方法全部参数经 keyConvertor 生成cacheNullValuefalse是否缓存 null 值condition未定义方法缓存条件表达式求值为 false 时不使用缓存在真实方法调用前求值postCondition未定义缓存更新条件求值为 false 时否决缓存更新在方法调用后求值可引用result缓存更新与删除CacheUpdate 与 CacheInvalidate再看个复杂点的例子它展示了缓存 key 的显式指定以及缓存的更新、删除public interface UserService { Cached(nameuserCache-, key#userId, expire 3600) User getUserById(long userId); CacheUpdate(nameuserCache-, key#user.userId, value#user) void updateUser(User user); CacheInvalidate(nameuserCache-, key#userId) void deleteUser(long userId); }第一个例子中没有指定 keyJetCache 会根据参数自动生成后两个例子显式指定了 key并演示了写操作时同步更新缓存CacheUpdate与删除缓存CacheInvalidate保证缓存与数据库最终一致。CacheUpdate见 CacheUpdate.java通过key与value两个表达式分别指定缓存 key 与缓存值还支持condition可引用#result与multikey/value 均为数组或Iterable时批量写入。CacheInvalidate见 CacheInvalidate.java支持multi批量失效且标注了Repeatable同一个方法上可以声明多个失效注解。从方法拦截实现看CacheUpdate/CacheInvalidate的处理逻辑位于 CacheHandler.java先执行原始方法invokeOrigin再依据表达式求值结果执行doInvalidate/doUpdate其中multi模式会先判断 key 是否为数组或Iterable再调用removeAll/putAll批量操作。三、大杀器自动刷新与加载保护穿透保护对于加载开销比较大的对象为了防止缓存未命中时的高并发访问打爆数据库JetCache 提供了自动刷新 加载保护的组合public interface SummaryService{ Cached(expire 3600, cacheType CacheType.REMOTE) CacheRefresh(refresh 1800, stopRefreshAfterLastAccess 3600, timeUnit TimeUnit.SECONDS) CachePenetrationProtect BigDecimal salesVolumeSummary(int timeId, long catagoryId); }这里有三层语义自动刷新CacheRefresh见 CacheRefresh.java指定refresh刷新间隔cacheType为REMOTE或BOTH时刷新行为是全局唯一的——即使应用服务器是一个集群也不会出现多台服务器同时刷新同一个 key 的情况。停刷机制stopRefreshAfterLastAccess指定该 key 自最后一次被访问后多久停止刷新。一个 key 的刷新任务自该 key 首次被访问后初始化若长时间不被访问超过stopRefreshAfterLastAccess后相关刷新任务会被自动移除避免无意义刷新浪费资源。穿透保护CachePenetrationProtect见 CachePenetrationProtect.java保证缓存未命中时一个 JVM 内只有一个线程去执行方法其它线程等待结果防止缓存击穿瞬间的并发请求打爆数据库。源码级原理集群内刷新互斥刷新任务运行在RefreshCache见 RefreshCache.java中。对于远程缓存每次刷新前先检查_#TS#时间戳 key确认是否到了刷新时刻若需要刷新则通过tryLockAndRun在_#RL#锁 key 上获取分布式锁只有拿到锁的节点才真正执行加载随后更新时间戳 key。若拿锁失败且是多级缓存则延迟 0.2 个刷新周期后把最新值从远程层回填到上层本地缓存refreshUpperCaches保证两级缓存数据一致。JVM 内单线程加载穿透保护的实现位于 AbstractCache.java 的synchronizedLoad。它用一个ConcurrentHashMap作为每 key 的锁池LoaderLock内含CountDownLatch第一个线程负责真实加载并countDown唤醒其余线程await等待结果若配置了penetrationProtectTimeout等待超时后该线程会自行执行加载避免长时间阻塞。Duration timeout config.getPenetrationProtectTimeout(); if (timeout null) { ll.signal.await(); } else { boolean ok ll.signal.await(timeout.toMillis(), TimeUnit.MILLISECONDS); if (!ok) { logger.info(loader wait timeout: timeout); return newLoader.apply(key); } }CacheRefresh还支持refreshLockTimeout属性默认 60 秒见 RefreshPolicy.java 中refreshLockTimeoutMillis 60 * 1000用于控制获取刷新锁的超时时间。四、更灵活的控制Cache API像 Map 一样用加在方法上的注解毕竟不能提供最灵活的控制所以 JetCache 提供了Cache接口见 Cache.java使用起来就像 Map 一样UserDO user userCache.get(12345L); userCache.put(12345L, loadUserFromDataBase(12345L)); userCache.remove(12345L); userCache.computeIfAbsent(1234567L, (key) - loadUserFromDataBase(1234567L));Cache接口同时提供 JSR-107 风格 APIget/put/remove/getAll/putIfAbsent等缓存访问出错时返回 null 而非抛异常与 JetCache 风格大写 APIGET/PUT/REMOVE/PUT_IF_ABSENT/GET_ALL等返回带结果码的CacheResult/CacheGetResult支持异步future()编程。computeIfAbsent在 key 无值时调用 loader 加载并回填缓存若配置了cacheNullValue见 CacheConfig.java则 null 值也会被缓存。五、用 CacheManager 创建缓存实例Cache 实例可以通过CacheManager创建2.7 版本中CreateCache注解已废弃。在相同 area 和 name 的情况下与Cached注解共用同一个 Cache 实例Autowired private CacheManager cacheManager; private CacheString, UserDO userCache; PostConstruct public void init() { QuickConfig qc QuickConfig.newBuilder(userCache) .expire(Duration.ofSeconds(100)) .cacheType(CacheType.BOTH) // two level cache .syncLocal(true) // invalidate local cache in all jvm process after update .build(); userCache cacheManager.getOrCreateCache(qc); }CacheManager见 CacheManager.java的getOrCreateCache(QuickConfig)是创建/获取缓存的统一入口QuickConfig见 QuickConfig.java的 Builder 支持链式配置Builder 方法对应语义newBuilder(name)/newBuilder(area, name)指定缓存名称及区域expire(Duration)/localExpire(Duration)过期时间 / 本地层过期时间localLimit(Integer)本地缓存容量上限cacheType(CacheType)LOCAL/REMOTE/BOTHsyncLocal(Boolean)更新后广播失效其它 JVM 的本地缓存keyConvertor(Function)自定义 Key 转换器valueEncoder / valueDecoder(Function)自定义 Value 序列化 / 反序列化器cacheNullValue(Boolean)是否缓存 null 值useAreaInPrefix(Boolean)area 是否进入远程 key 前缀penetrationProtect(Boolean)/penetrationProtectTimeout(Duration)穿透保护及等待超时refreshPolicy(RefreshPolicy)自动刷新策略loader(CacheLoader)值加载器配合刷新使用这里syncLocal(true)依赖 2.7 的广播能力两级缓存更新后通过远程缓存的 broadcast channel 通知所有 JVM 失效本地缓存。广播实现可参考 RedisBroadcastManager.javachannel 名称在 yml 中通过jetcache.remote.${area}.broadcastChannel配置多个服务可决定是否共用同一个 channel避免广播风暴。六、Low Level APIBuilder 直接构建缓存也可以通过类似 Guava Cache / Caffeine 的 Builder 创建缓存这是 low level API不依赖 SpringGenericObjectPoolConfig pc new GenericObjectPoolConfig(); pc.setMinIdle(2); pc.setMaxIdle(10); pc.setMaxTotal(10); JedisPool pool new JedisPool(pc, 127.0.0.1, 6379); CacheLong, UserDO userCache RedisCacheBuilder.createRedisCacheBuilder() .keyConvertor(Fastjson2KeyConvertor.INSTANCE) .valueEncoder(JavaValueEncoder.INSTANCE) .valueDecoder(JavaValueDecoder.INSTANCE) .jedisPool(pool) .keyPrefix(userCache-) .expireAfterWrite(200, TimeUnit.SECONDS) .buildCache();keyConvertorKey 转换策略内置Fastjson2KeyConvertor/JacksonKeyConvertor/Jackson3KeyConvertor等见 support 包valueEncoder/valueDecoderValue 序列化策略内置 Java 序列化、Kryo / Kryo5、Fastjson2、Jackson 等实现keyPrefix远程缓存 key 前缀expireAfterWrite写入后过期时间。Redis 的几种访问方式分别对应 RedisCacheBuilder.java、RedisLettuceCacheBuilder.java、RedisSpringDataCacheBuilder.java、RedissonCacheBuilder.java。安全提示JetCache 2.8.x 默认开启了反序列化安全过滤器只允许常见 Java 包和 JetCache 包下的类被反序列化。如果缓存值包含自定义类如UserDO、OrderDO需要配置允许列表详见 配置文档 中的反序列化过滤器配置章节。具体而言详见 docs/CN/Config.md默认允许java.lang、java.util.、java.time.、java.math、java.net、com.alicp.jetcache.自定义类可通过 yml 的jetcache.decodeFilterAllowPatterns添加支持前缀匹配com.example.、包名匹配com.example、精确匹配完整类名三种模式拒绝列表内置 gadget chain、java.lang.Runtime、com.sun.等优先级最高、不可被允许规则覆盖非 Spring Boot 场景可用DecodeFilter.getDefault().addAllowPatterns(com.example.)编程式配置。七、异步 Cache APICache接口支持异步。大写 API 返回的CacheGetResult见 CacheGetResult.java内部持有CompletionStageResultData调用future()即可获得异步编程能力CacheGetResult r cache.GET(userId); CompletionStageResultData future r.future(); future.thenRun(() - { if(r.isSuccess()){ System.out.println(r.getValue()); } });说明调用getResultCode()/isSuccess()/getValue()会阻塞直到缓存操作完成而调用future()则进入异步模式适合与 CompletableFuture 组合编排避免线程阻塞在远程 IO 上。八、分布式锁JetCache 的Cache接口提供了不严格的分布式锁能力基于远程缓存的PUT_IF_ABSENT原子语义实现cache.tryLockAndRun(key, 60, TimeUnit.SECONDS, () - heavyDatabaseOperation());tryLock(key, expire, timeUnit)非阻塞尝试获取锁成功返回AutoReleaseLockAutoCloseable失败返回 nulltryLockAndRun(key, expire, timeUnit, action)获取锁成功后执行action返回是否执行成功。从 Cache.java 的实现看加锁通过PUT_IF_ABSENT写入 UUID 并带过期时间完成解锁通过REMOVE完成且解锁失败会按tryLockUnlockCount重试若缓存访问失败还会按tryLockInquiryCount查询锁归属。锁的默认行为参数tryLockLockCount、tryLockInquiryCount、tryLockUnlockCount等定义在 CacheConfig.java。注意多级缓存MultiLevelCache会使用最底层远程缓存来支持锁操作参见 MultiLevelCache.java 的tryLock。九、用 Cache API 配置自动刷新使用 Cache 实例也可以配置自动刷新PostConstruct public void init() { QuickConfig qc QuickConfig.newBuilder(userCache) .refreshPolicy(RefreshPolicy.newPolicy(60, TimeUnit.SECONDS)) .build(); userCache cacheManager.getOrCreateCache(qc); }low level API 的 Builder 同样可以配置自动刷新此时需要指定loader加载器CacheString, Long orderSumCache RedisCacheBuilder.createRedisCacheBuilder() // ......省略 .refreshPolicy(RefreshPolicy.newPolicy(60, TimeUnit.SECONDS)) .loader(this::loadOrderSumFromDatabase) .buildCache();RefreshPolicy.newPolicy(60, TimeUnit.SECONDS)表示每 60 秒刷新一次还可以链式调用stopRefreshAfterLastAccess(...)与refreshLockTimeout(...)。刷新任务由 RefreshCache.java 基于JetCacheExecutor.heavyIOExecutor()的scheduleWithFixedDelay调度key 首次被访问时才创建对应刷新任务并在长期无访问后自动取消。十、支持的缓存系统与扩展性当前支持的缓存系统包括以下 4 个而且支持一种新的缓存也非常容易通过实现Cache/AbstractCache及对应的 Builder 即可缓存类型说明Caffeine本地内存高性能本地缓存见 CaffeineCache.javaLinkedHashMap本地内存JetCache 自己实现的简易 LRU 缓存见 LinkedHashMapCache.javaAlibaba Tair远程相关实现未在 GitHub 开源Redis远程含 jedis、lettuce、spring-data、redisson 四种访问方式十一、系统需求与版本兼容使用 JetCache 的系统需求以当前仓库为准JDKjetcache 2.8 需要 Java 17 以上版本jetcache 2.7 及以下版本支持 Java 8Spring Framework可选如果用 low level API 则不需要jetcache 2.8 需要 6.x 以上jetcache 2.7 需要 5.2.4 以上Spring Boot可选jetcache 2.8 需要 3.x 以上jetcache 2.7 需要 2.2.5 以上。如果只使用 low level APIBuilder 构建缓存可以不依赖 Spring 容器仅引入jetcache-core与对应的支持模块如jetcache-redis即可。十二、自动统计与监控JetCache 会对所有 Cache 实例和方法缓存进行自动统计。统计由CacheMonitor完成默认实现为 DefaultCacheMonitor.java每次缓存操作GET / PUT / REMOVE / LOAD 等都会产生对应的CacheEvent见 event 包经AbstractCache.notify分发到CacheConfig中注册的 monitors累计得到命中率、耗时等CacheStat。统计间隔可通过配置jetcache.statIntervalMinutes指定0 表示不统计详见 docs/CN/Config.md。十三、全局配置参考使用 Spring Boot 时可以在 application.yml 中配置节选自 docs/CN/Config.mdjetcache: statIntervalMinutes: 15 areaInCacheName: false hidePackages: com.alibaba local: default: type: caffeine limit: 100 keyConvertor: fastjson2 expireAfterWriteInMillis: 100000 remote: default: type: redis keyConvertor: fastjson2 broadcastChannel: projectA valueEncoder: java valueDecoder: java poolConfig: minIdle: 5 maxIdle: 20 maxTotal: 50 host: ${redis.host} port: ${redis.port}${area}对应Cached注解的area属性注解上未指定时默认值是default。关于超时时间的优先级规则为put 方法上显式指定的超时 Cache 实例默认超时注解expire属性 yml 全局配置expireAfterWriteInMillis 无穷大。未使用 Spring Boot 时直接配置GlobalCacheConfig是类似的参考快速入门教程。总结有了 JetCache我们就可以更方便地基于统一的接口访问缓存注解声明让方法缓存一行接入Cache接口让编程式访问像 Map 一样简单自动刷新 穿透保护解决了缓存击穿与数据过期问题两级缓存配合广播失效在集群环境下兼顾性能与一致性。更多文档可以在仓库的 docs 目录中找到含中英文的 快速入门、方法缓存、配置说明、Redis 接入 等示例代码可参考 samples 目录。赞分享后端缓存抽象【免费下载链接】jetcacheJetCache is a Java cache framework.项目地址https://gitcode.com/gh_mirrors/je/jetcache点击查看免费下载相关推荐Midway 缓存组件实践指南基于 cache-manager 的内存、Redis、多级缓存与自动刷新Midway 缓存组件实践指南基于 cache manager 的内存、Redis、多级缓存与自动刷新 Midway 官方在 cache manager ht后端微服务云原生Midway 缓存组件实战基于 cache-manager v5 的多级缓存、自动刷新与装饰器缓存Midway 缓存组件实战基于 cache manager v5 的多级缓存、自动刷新与装饰器缓存 缓存是提升应用性能最简单有效的技术之一把热点数据放到更靠后端微服务云原生Midway 缓存组件 midwayjs/cache-manager 完全指南多 Store、多级缓存与自动刷新Midway 缓存组件 midwayjs/cache manager 完全指南多 Store、多级缓存与自动刷新 缓存是提升应用性能最简单也最有效的技术之一后端微服务云原生上一篇qmc-decoder终极指南一键解锁加密音乐让音乐播放无界限下一篇你的QQ音乐加密文件为何在其他设备上无法播放3步解锁音频自由创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询