【Hystrix】【源码+图解】【四】缓存功能

【Hystrix】【源码+图解】【三】执行Hystrix命令

7 缓存

为了方便分析,与缓存无关的代码暂且略过

    public Observable<R> toObservable() {
        ......
        return Observable.defer(new Func0<Observable<R>>() {
            @Override
            public Observable<R> call() {
                ......
                // 缓存开启标志【7.1】
                final boolean requestCacheEnabled = isRequestCachingEnabled();
                // 缓存key【7.2】
                final String cacheKey = getCacheKey();
                // 判断是否开启了缓存模式
                if (requestCacheEnabled) {
                    // 获取缓存【7.3】
                    HystrixCommandResponseFromCache<R> fromCache = (HystrixCommandResponseFromCache<R>) requestCache.get(cacheKey);
                    ......
                }
                // 缓存不存在则创建新值
                Observable<R> hystrixObservable = Observable.defer(applyHystrixSemantics).map(wrapWithAllOnNextHooks);
                ......
                    HystrixCachedObservable<R> toCache = HystrixCachedObservable.from(hystrixObservable, _cmd);
                    // (4)存放缓存,多线程环境,如果另一个线程已经创建了就用它创建好的
                    HystrixCommandResponseFromCache<R> fromCache = (HystrixCommandResponseFromCache<R>) requestCache.putIfAbsent(cacheKey, toCache);
                    ......
            }
        });
    }

7.1 缓存开启标志

    protected boolean isRequestCachingEnabled() {
        return properties.requestCacheEnabled().get() && getCacheKey() != null;
    }

从代码中可以看到缓存开启标志是从properties直接读取的,我们看下实践中如何设置

    // 默认值为true
    @HystrixCommand(commandProperties = { @HystrixProperty(name = "requestCache.enabled", value = "true") })
    public String test() {
        return "MyHystrix";
    }

7.2 缓存key

    @Override
    protected String getCacheKey() {
        String key = null;
        if (cacheResultInvocationContext != null) {
            HystrixGeneratedCacheKey hystrixGeneratedCacheKey =
                    defaultCacheKeyGenerator.generateCacheKey(cacheResultInvocationContext);
            key = hystrixGeneratedCacheKey.getCacheKey();
        }
        return key;
    }

key的获得最终会调用HystrixCacheKeyGenerator.generateCacheKey(...)生成,形式有四种,我们先举个例子,然后对照着源码分析。

public class UserFacadeImpl implements UserFacade{
    
    // key: 空值
    @HystrixCommand
    @CacheResult
    public void cacheKey1() {
        
    }
    
    // key: key的具体值
    @HystrixCommand
    @CacheResult
    public void cacheKey2(@CacheKey String key) {
        
    }
    
    // key: obj.keyCol
    // 如果不指定属性,则调用toString()的值
    // 如果指定了属性keyCol,则MyKeyObj对象中必须存在属性keyCol,否则报异常
    @HystrixCommand
    @CacheResult
    public void cacheKey3(@CacheKey("keyCol") MyKeyObj obj) {
        
    }
    
    // key: generateCacheKey(...)
    // 当前类中必须存在generateCacheKey方法,否则报异常
    // generateCacheKey的参数必须与cacheKey4方法的参数一致,否则报异常
    // generateCacheKey的返回值必须为String类型,否则报异常
    @HystrixCommand
    @CacheResult(cacheKeyMethod = "generateCacheKey")
    public void cacheKey4(String key) {
        
    }
    
    public String generateCacheKey(String key) {
        return "generateCacheKey";
    }
    
    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    public static class MyKeyObj {
        String keyCol;
    }
}

源码分析

// HystrixCacheKeyGenerator
	public HystrixGeneratedCacheKey generateCacheKey(...) throws HystrixCacheKeyGenerationException {
        MethodExecutionAction cacheKeyMethod = cacheInvocationContext.getCacheKeyMethod();
        // 判断方法是否指定cacheKeyMethod
        if (cacheKeyMethod != null) {
            try {
                // cacheKey4()方法,调用generateCacheKey获取key
                return new DefaultHystrixGeneratedCacheKey((String) cacheKeyMethod.execute(cacheInvocationContext.getExecutionType()));
            } catch (Throwable throwable) {
                throw new HystrixCacheKeyGenerationException(throwable);
            }
        } else {
            // 判断方法是否存在参数
            if (cacheInvocationContext.hasKeyParameters()) {
                StringBuilder cacheKeyBuilder = new StringBuilder();
                for (CacheInvocationParameter parameter : cacheInvocationContext.getKeyParameters()) {
                    CacheKey cacheKey = parameter.getCacheKeyAnnotation();
                    if (cacheKey != null && StringUtils.isNotBlank(cacheKey.value())) {
                        // cacheKey3()方法,读取对象中对应列的值
                        appendPropertyValue(cacheKeyBuilder, Arrays.asList(StringUtils.split(cacheKey.value(), ".")), parameter.getValue());
                    } else {
                        // cacheKey2()方法,直接读值
                        cacheKeyBuilder.append(parameter.getValue());
                    }
                }
                return new DefaultHystrixGeneratedCacheKey(cacheKeyBuilder.toString());
            } else {
                // cacheKey1()方法,默认为空
                return DefaultHystrixGeneratedCacheKey.EMPTY;
            }
        }
    }

7.3 获取缓存

创建HystrixRequestCache
    protected final HystrixRequestCache requestCache;

    protected AbstractCommand(......) {
        ......
        this.requestCache = HystrixRequestCache.getInstance(this.commandKey, this.concurrencyStrategy);
        ......
    }

HystrixRequestCache.getInstance(...)

    public static HystrixRequestCache getInstance(HystrixCommandKey key, HystrixConcurrencyStrategy concurrencyStrategy) {
        return getInstance(new RequestCacheKey(key, concurrencyStrategy), concurrencyStrategy);
    }

    private static HystrixRequestCache getInstance(RequestCacheKey rcKey, HystrixConcurrencyStrategy concurrencyStrategy) {
        HystrixRequestCache c = caches.get(rcKey);
        // 通过rcKey从缓存中获取
        if (c == null) {
            // 不存在则新建
            HystrixRequestCache newRequestCache = new HystrixRequestCache(rcKey, concurrencyStrategy);
            // 多线程环境,如果其他线程已经创建则使用已经创建好的,否则使用newRequestCache
            HystrixRequestCache existing = caches.putIfAbsent(rcKey, newRequestCache);
            if (existing == null) {
                c = newRequestCache;
            } else {
                c = existing;
            }
        }
        return c;
    }

从这里看出HystrixRequestCache是由commandKeyconcurrencyStrategy两者创建的,同一个请求中concurrencyStrategy一般不会变,所以对于同一个commandKey的缓存都会放在一个HystrixRequestCache里

获取缓存HystrixRequestCache.get(cacheKey)
    /* package */<T> HystrixCachedObservable<T> get(String cacheKey) {
        ValueCacheKey key = getRequestCacheKey(cacheKey);
        if (key != null) {
            ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>> cacheInstance = requestVariableForCache.get(concurrencyStrategy);
            ......
            return (HystrixCachedObservable<T>) cacheInstance.get(key);
        }
        return null;
    }

源码涉及很多数据结构,简单理解就是HystrixRequestCache类似一个map结构,键为cacheKey构建的ValueCacheKey,值为HystrixCachedObservable。

未完待续

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值