聊聊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