当前位置: 首页 > news >正文

聊聊JetCache的缓存构建

本文主要研究一下JetCache的缓存构建

invokeWithCached

com/alicp/jetcache/anno/method/CacheHandler.java

    private static Object invokeWithCached(CacheInvokeContext context)throws Throwable {CacheInvokeConfig cic = context.getCacheInvokeConfig();CachedAnnoConfig cac = cic.getCachedAnnoConfig();Cache cache = context.getCacheFunction().apply(context, cac);if (cache == null) {logger.error("no cache with name: " + context.getMethod());return invokeOrigin(context);}Object key = ExpressionUtil.evalKey(context, cic.getCachedAnnoConfig());if (key == null) {return loadAndCount(context, cache, key);}if (!ExpressionUtil.evalCondition(context, cic.getCachedAnnoConfig())) {return loadAndCount(context, cache, key);}try {CacheLoader loader = new CacheLoader() {@Overridepublic Object load(Object k) throws Throwable {Object result = invokeOrigin(context);context.setResult(result);return result;}@Overridepublic boolean vetoCacheUpdate() {return !ExpressionUtil.evalPostCondition(context, cic.getCachedAnnoConfig());}};Object result = cache.computeIfAbsent(key, loader);return result;} catch (CacheInvokeException e) {throw e.getCause();}}

invokeWithCached先通过context.getCacheFunction().apply(context, cac)去获取缓存

setCacheFunction

com/alicp/jetcache/anno/support/CacheContext.java

    public CacheInvokeContext createCacheInvokeContext(ConfigMap configMap) {CacheInvokeContext c = newCacheInvokeContext();c.setCacheFunction((invokeContext, cacheAnnoConfig) -> {Cache cache = cacheAnnoConfig.getCache();if (cache == null) {if (cacheAnnoConfig instanceof CachedAnnoConfig) {cache = createCacheByCachedConfig((CachedAnnoConfig) cacheAnnoConfig, invokeContext);} else if ((cacheAnnoConfig instanceof CacheInvalidateAnnoConfig) || (cacheAnnoConfig instanceof CacheUpdateAnnoConfig)) {CacheInvokeConfig cacheDefineConfig = configMap.getByCacheName(cacheAnnoConfig.getArea(), cacheAnnoConfig.getName());if (cacheDefineConfig == null) {String message = "can't find @Cached definition with area=" + cacheAnnoConfig.getArea()+ " name=" + cacheAnnoConfig.getName() +", specified in " + cacheAnnoConfig.getDefineMethod();CacheConfigException e = new CacheConfigException(message);logger.error("Cache operation aborted because can't find @Cached definition", e);return null;}cache = createCacheByCachedConfig(cacheDefineConfig.getCachedAnnoConfig(), invokeContext);}cacheAnnoConfig.setCache(cache);}return cache;});return c;}

createCacheInvokeContext设置了cacheFunction,使用了双重检锁去构建cache,对于CachedAnnoConfig是走了createCacheByCachedConfig

createCacheByCachedConfig

com/alicp/jetcache/anno/support/CacheContext.java

    private Cache createCacheByCachedConfig(CachedAnnoConfig ac, CacheInvokeContext invokeContext) {String area = ac.getArea();String cacheName = ac.getName();if (CacheConsts.isUndefined(cacheName)) {cacheName = configProvider.createCacheNameGenerator(invokeContext.getHiddenPackages()).generateCacheName(invokeContext.getMethod(), invokeContext.getTargetObject());}Cache cache = __createOrGetCache(ac, area, cacheName);return cache;}public Cache __createOrGetCache(CachedAnnoConfig cachedAnnoConfig, String area, String cacheName) {String fullCacheName = area + "_" + cacheName;Cache cache = cacheManager.getCacheWithoutCreate(area, cacheName);if (cache == null) {synchronized (this) {cache = cacheManager.getCacheWithoutCreate(area, cacheName);if (cache == null) {if (globalCacheConfig.isAreaInCacheName()) {// for compatible reason, if we use default configuration, the prefix should same to that version <=2.4.3cache = buildCache(cachedAnnoConfig, area, fullCacheName);} else {cache = buildCache(cachedAnnoConfig, area, cacheName);}cacheManager.putCache(area, cacheName, cache);}}}return cache;}    

__createOrGetCache再次使用双重检锁通过buildCache去构建Cache,默认globalCacheConfig.isAreaInCacheName()为false,构建完放入cacheManager

buildCache

com/alicp/jetcache/anno/support/CacheContext.java

    protected Cache buildCache(CachedAnnoConfig cachedAnnoConfig, String area, String cacheName) {Cache cache;if (cachedAnnoConfig.getCacheType() == CacheType.LOCAL) {cache = buildLocal(cachedAnnoConfig, area);} else if (cachedAnnoConfig.getCacheType() == CacheType.REMOTE) {cache = buildRemote(cachedAnnoConfig, area, cacheName);} else {Cache local = buildLocal(cachedAnnoConfig, area);Cache remote = buildRemote(cachedAnnoConfig, area, cacheName);boolean useExpireOfSubCache = cachedAnnoConfig.getLocalExpire() > 0;cache = MultiLevelCacheBuilder.createMultiLevelCacheBuilder().expireAfterWrite(remote.config().getExpireAfterWriteInMillis(), TimeUnit.MILLISECONDS).addCache(local, remote).useExpireOfSubCache(useExpireOfSubCache).cacheNullValue(cachedAnnoConfig.isCacheNullValue()).buildCache();}cache.config().setRefreshPolicy(cachedAnnoConfig.getRefreshPolicy());cache = new CacheHandler.CacheHandlerRefreshCache(cache);cache.config().setCachePenetrationProtect(globalCacheConfig.isPenetrationProtect());PenetrationProtectConfig protectConfig = cachedAnnoConfig.getPenetrationProtectConfig();if (protectConfig != null) {cache.config().setCachePenetrationProtect(protectConfig.isPenetrationProtect());cache.config().setPenetrationProtectTimeout(protectConfig.getPenetrationProtectTimeout());}if (configProvider.getCacheMonitorManager() != null) {configProvider.getCacheMonitorManager().addMonitors(area, cacheName, cache);}return cache;}

buildCache根据CacheType去构建,对于REMOTE是执行buildRemote

buildRemote

    protected Cache buildRemote(CachedAnnoConfig cachedAnnoConfig, String area, String cacheName) {ExternalCacheBuilder cacheBuilder = (ExternalCacheBuilder) globalCacheConfig.getRemoteCacheBuilders().get(area);if (cacheBuilder == null) {throw new CacheConfigException("no remote cache builder: " + area);}cacheBuilder = (ExternalCacheBuilder) cacheBuilder.clone();if (cachedAnnoConfig.getExpire() > 0 ) {cacheBuilder.expireAfterWrite(cachedAnnoConfig.getExpire(), cachedAnnoConfig.getTimeUnit());}if (cacheBuilder.getConfig().getKeyPrefix() != null) {cacheBuilder.setKeyPrefix(cacheBuilder.getConfig().getKeyPrefix() + cacheName);} else {cacheBuilder.setKeyPrefix(cacheName);}if (!CacheConsts.isUndefined(cachedAnnoConfig.getKeyConvertor())) {cacheBuilder.setKeyConvertor(configProvider.parseKeyConvertor(cachedAnnoConfig.getKeyConvertor()));}if (!CacheConsts.isUndefined(cachedAnnoConfig.getSerialPolicy())) {cacheBuilder.setValueEncoder(configProvider.parseValueEncoder(cachedAnnoConfig.getSerialPolicy()));cacheBuilder.setValueDecoder(configProvider.parseValueDecoder(cachedAnnoConfig.getSerialPolicy()));}cacheBuilder.setCacheNullValue(cachedAnnoConfig.isCacheNullValue());return cacheBuilder.buildCache();}

这里获取remote的cacheBuilder,进行clone,然后根据cachedAnnoConfig进行属性覆盖,然后执行cacheBuilder.buildCache()构建;这里keyPrefix默认为null,所以这里的keyPrefix为不带aera的cacheName;ExternalCacheBuilder有MockRemoteCacheBuilder、RedisLettuceCacheBuilder两个子类。

小结

JetCache延迟构建Cache,通过CacheContext.buildCache根据cacheType进行构建。

doc

  • Builder

相关文章:

  • 【Python】超类与父类
  • 关于数据湖和数据仓的一些概念
  • 抢跑「中央计算+区域控制」市场,芯驰科技高端智控MCU“芯”升级
  • AcroForm JavaScript Promise 对象应用示例: 异步加载PDF文件
  • JS,ES,TS三者什么区别
  • python如何设置excel单元格边框样式
  • 云图库和黑马点评的项目学习经验
  • 数字IC后端设计实现 | 如何自动删除Innovus 中冗余的hold buffer?
  • NAT/代理服务器/内网穿透
  • SpringBoot整合MQTT实战:基于EMQX构建高可靠物联网通信,从零到一实现设备云端双向对话
  • K8S Ingress 实现金丝雀(灰度)发布
  • NVMe简介1
  • FFMPEG 与 mp4
  • FunASR:语音识别与合成一体化,企业级开发实战详解
  • Turborepo + Vite + Next.js + Shadcn Monorepo 项目构建
  • MoonBit正式入驻GitCode!AI时代的编程语言新星,开启高性能开发新纪元
  • 【面试 · 五】CSS个别重点总结
  • 【内网渗透】——S4u2扩展协议提权以及KDC欺骗提权
  • Xcode报错:“Set `maskView` to `nil` before adding it as a subview of ZFMaskView
  • 嵌入式培训之数据结构学习(三)gdb调试
  • 上海市国防动员办公室副主任吴斌接受审查调查
  • 法学联合书单|法庭上的妇女
  • 美国三大指数全线高开:纳指涨逾4%,大型科技股、中概股大涨
  • 美国“贸易战”前线的本土受害者:安静的洛杉矶港和准备关门的小公司
  • 李公明 | 一周画记:印巴交火会否升级为第四次印巴战争?
  • 普京提议重启俄乌直接谈判后,特朗普表态了