【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
是由commandKey
和concurrencyStrategy
两者创建的,同一个请求中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。
未完待续