HystrixRequestCache

  请求缓存。内部是一个静态ConcurrentHashMap存储各个命令的缓存器,RequestCacheKey为key,HystrixRequestCache为value。

private final static ConcurrentHashMap<RequestCacheKey, HystrixRequestCache> caches = new ConcurrentHashMap<RequestCacheKey, HystrixRequestCache>();

  RequestCacheKey由两部分组成:当前command的keyname,指定HystrixConcurrencyStrategy对象。

private static class RequestCacheKey {
private final short type; // used to differentiate between Collapser/Command if key is same between them
private final String key;
private final HystrixConcurrencyStrategy concurrencyStrategy; private RequestCacheKey(HystrixCommandKey commandKey, HystrixConcurrencyStrategy concurrencyStrategy) {
type = 1;
if (commandKey == null) {
this.key = null;
} else {
this.key = commandKey.name();
}
this.concurrencyStrategy = concurrencyStrategy;
}
...

  通过getInstance来获取每个命令的缓冲器。

public static HystrixRequestCache getInstance(HystrixCommandKey key, HystrixConcurrencyStrategy concurrencyStrategy) {
return getInstance(new RequestCacheKey(key, concurrencyStrategy), concurrencyStrategy);
} public static HystrixRequestCache getInstance(HystrixCollapserKey key, HystrixConcurrencyStrategy concurrencyStrategy) {
return getInstance(new RequestCacheKey(key, concurrencyStrategy), concurrencyStrategy);
} private static HystrixRequestCache getInstance(RequestCacheKey rcKey, HystrixConcurrencyStrategy concurrencyStrategy) {
HystrixRequestCache c = caches.get(rcKey);
if (c == null) {
HystrixRequestCache newRequestCache = new HystrixRequestCache(rcKey, concurrencyStrategy);
HystrixRequestCache existing = caches.putIfAbsent(rcKey, newRequestCache);
if (existing == null) {
// we won so use the new one
c = newRequestCache;
} else {
// we lost so use the existing
c = existing;
}
}
return c;
}

  HystrixRequestCache提供了get来获取指定key缓存,提供了putIfAbsent来存储指定key的缓存内容。内部是一个ConcurrentHashMap存储缓存内容,ValueCacheKey为key,HystrixCachedObservable为value。缓存的内容是请求级别共享的,所以放在一个HystrixRequestVariableHolder中。

private static final HystrixRequestVariableHolder<ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>>> requestVariableForCache = new HystrixRequestVariableHolder<ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>>>(new HystrixRequestVariableLifecycle<ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>>>() {

        @Override
public ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>> initialValue() {
return new ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>>();
} @Override
public void shutdown(ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>> value) {
// nothing to shutdown
} });

  ValueCacheKey由三部分组成:RequestCacheKey对象和指定String类型 key。

private static class ValueCacheKey {
private final RequestCacheKey rvKey;
private final String valueCacheKey;
private ValueCacheKey(RequestCacheKey rvKey, String valueCacheKey) {
this.rvKey = rvKey;
this.valueCacheKey = valueCacheKey;
} ... }

  get和putIfAbsent方法

@SuppressWarnings({ "unchecked" })
/* package */<T> HystrixCachedObservable<T> get(String cacheKey) {
ValueCacheKey key = getRequestCacheKey(cacheKey);
if (key != null) {
ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>> cacheInstance = requestVariableForCache.get(concurrencyStrategy);
if (cacheInstance == null) {
throw new IllegalStateException("Request caching is not available. Maybe you need to initialize the HystrixRequestContext?");
}
/* look for the stored value */
return (HystrixCachedObservable<T>) cacheInstance.get(key);
}
return null;
} @SuppressWarnings({ "unchecked" })
/* package */<T> HystrixCachedObservable<T> putIfAbsent(String cacheKey, HystrixCachedObservable<T> f) {
ValueCacheKey key = getRequestCacheKey(cacheKey);
if (key != null) {
/* look for the stored value */
ConcurrentHashMap<ValueCacheKey, HystrixCachedObservable<?>> cacheInstance = requestVariableForCache.get(concurrencyStrategy);
if (cacheInstance == null) {
throw new IllegalStateException("Request caching is not available. Maybe you need to initialize the HystrixRequestContext?");
}
HystrixCachedObservable<T> alreadySet = (HystrixCachedObservable<T>) cacheInstance.putIfAbsent(key, f);
if (alreadySet != null) {
// someone beat us so we didn't cache this
return alreadySet;
}
}
// we either set it in the cache or do not have a cache key
return null;
}

HystrixCachedObservable

  内部使用了ReplaySubject缓存了originalObservable的结果

 protected final Subscription originalSubscription;
protected final Observable<R> cachedObservable;
private volatile int outstandingSubscriptions = 0; protected HystrixCachedObservable(final Observable<R> originalObservable) {
ReplaySubject<R> replaySubject = ReplaySubject.create();
this.originalSubscription = originalObservable
.subscribe(replaySubject); this.cachedObservable = replaySubject
.doOnUnsubscribe(new Action0() {
@Override
public void call() {
outstandingSubscriptions--;
if (outstandingSubscriptions == 0) {
originalSubscription.unsubscribe();
}
}
})
.doOnSubscribe(new Action0() {
@Override
public void call() {
outstandingSubscriptions++;
}
});
} public static <R> HystrixCachedObservable<R> from(Observable<R> o, AbstractCommand<R> originalCommand) {
return new HystrixCommandResponseFromCache<R>(o, originalCommand);
} public static <R> HystrixCachedObservable<R> from(Observable<R> o) {
return new HystrixCachedObservable<R>(o);
} public Observable<R> toObservable() {
return cachedObservable;
} public void unsubscribe() {
originalSubscription.unsubscribe();
}

HystrixCommandResponseFromCache

  HystrixCachedObservable的子类,HystrixCommand实际使用来缓存结果的类。该类的作用是,当使用缓存结果时,会同步之前命令的运行结果

public class HystrixCommandResponseFromCache<R> extends HystrixCachedObservable<R> {
private final AbstractCommand<R> originalCommand; /* package-private */ HystrixCommandResponseFromCache(Observable<R> originalObservable, final AbstractCommand<R> originalCommand) {
super(originalObservable);
this.originalCommand = originalCommand;
} public Observable<R> toObservableWithStateCopiedInto(final AbstractCommand<R> commandToCopyStateInto) {
final AtomicBoolean completionLogicRun = new AtomicBoolean(false); return cachedObservable
.doOnError(new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
if (completionLogicRun.compareAndSet(false, true)) {
commandCompleted(commandToCopyStateInto);
}
}
})
.doOnCompleted(new Action0() {
@Override
public void call() {
if (completionLogicRun.compareAndSet(false, true)) {
commandCompleted(commandToCopyStateInto);
}
}
})
.doOnUnsubscribe(new Action0() {
@Override
public void call() {
if (completionLogicRun.compareAndSet(false, true)) {
commandUnsubscribed(commandToCopyStateInto);
}
}
});
} private void commandCompleted(final AbstractCommand<R> commandToCopyStateInto) {
commandToCopyStateInto.executionResult = originalCommand.executionResult;
} private void commandUnsubscribed(final AbstractCommand<R> commandToCopyStateInto) {
commandToCopyStateInto.executionResult = commandToCopyStateInto.executionResult.addEvent(HystrixEventType.CANCELLED);
commandToCopyStateInto.executionResult = commandToCopyStateInto.executionResult.setExecutionLatency(-1);
}
}

hystrix源码之请求缓存的更多相关文章

  1. hystrix源码之请求合并

    请求合并 使用HystrixObservableCollapser可以将参数不同,但执行过程相同的调用合并执行.当调用observe.toObservable方法时,会向RequestCollapse ...

  2. 【一起学源码-微服务】Hystrix 源码一:Hystrix基础原理与Demo搭建

    说明 原创不易,如若转载 请标明来源! 欢迎关注本人微信公众号:壹枝花算不算浪漫 更多内容也可查看本人博客:一枝花算不算浪漫 前言 前情回顾 上一个系列文章讲解了Feign的源码,主要是Feign动态 ...

  3. 【转】MaBatis学习---源码分析MyBatis缓存原理

    [原文]https://www.toutiao.com/i6594029178964673027/ 源码分析MyBatis缓存原理 1.简介 在 Web 应用中,缓存是必不可少的组件.通常我们都会用 ...

  4. Tomcat源码分析——请求原理分析(中)

    前言 在<TOMCAT源码分析——请求原理分析(上)>一文中已经介绍了关于Tomcat7.0处理请求前作的初始化和准备工作,请读者在阅读本文前确保掌握<TOMCAT源码分析——请求原 ...

  5. Mybatis源码手记-从缓存体系看责任链派发模式与循环依赖企业级实践

    一.缓存总览 Mybatis在设计上处处都有用到的缓存,而且Mybatis的缓存体系设计上遵循单一职责.开闭原则.高度解耦.及其精巧,充分的将缓存分层,其独到之处可以套用到很多类似的业务上.这里将主要 ...

  6. 第三篇:白话tornado源码之请求来了

    上一篇<白话tornado源码之待请求阶段>中介绍了tornado框架在客户端请求之前所做的准备(下图1.2部分),本质上就是创建了一个socket服务端,并进行了IP和端口的绑定,但是未 ...

  7. jQuery1.9.1源码分析--数据缓存Data模块

    jQuery1.9.1源码分析--数据缓存Data模块 阅读目录 jQuery API中Data的基本使用方法介绍 jQuery.acceptData(elem)源码分析 jQuery.data(el ...

  8. lodash源码分析之缓存使用方式的进一步封装

    在世界上所有的民族之中,支配着他们的喜怒选择的并不是天性,而是他们的观点. --卢梭<社会与契约论> 本文为读 lodash 源码的第九篇,后续文章会更新到这个仓库中,欢迎 star:po ...

  9. Hystrix源码解析

    1. Hystrix源码解析 1.1. @HystrixCommand原理 直接通过Aspect切面来做的 1.2. feign hystrix原理 它的本质原理就是对HystrixCommand的动 ...

随机推荐

  1. Docker日常使用方式

    前提 在安装docker之前,建议你设置系统的国内镜像源先哦,很快~嗯,快. 阿里云镜像源:https://developer.aliyun.com/mirror/ 安装 安装docker 下面都是官 ...

  2. three.js 制作逻辑转体游戏(上)

    今天郭先生又出来制作游戏了,最近有小伙伴要做一个逻辑转体小游戏,我怎么能不先来试试呢.玩法可以看上面的连接,下面附几张图.线案例请点击博客原文. 游戏规则不懂得可以看自行百度哈,其实玩起来还挺有难度的 ...

  3. API、Win32 SDK、Win32项目、MFC、Windows窗体应用程序的区别

    [原]API.Win32 SDK.Win32项目.MFC.Windows窗体应用程序的区别 首先来看一下每一个术语的定义: API:Application Programming Interface. ...

  4. [PyTorch 学习笔记] 1.2 Tensor(张量)介绍

    本章代码: https://github.com/zhangxiann/PyTorch_Practice/blob/master/lesson1/tensor_introduce1.py https: ...

  5. cinder api启动过程源码分析

    1.启动cinder-api服务 当你通过cinder-api命令(如:/usr/bin/cinder-api --config-file /etc/cinder/cinder.conf)启动api服 ...

  6. 发布 npm遇到的问题

    npm publish 遇到 403 怎么办? 这说明你没有切换到 npm 原始源,那么你只需要用 npm config delete registry 删除淘宝源,然后再 publish. publ ...

  7. Mybatis动态语句

    If元素If元素是简单的条件判断逻辑,满足制定条件时追加if元素的SQL,不满足条件时不追加,使用格式如下: <select ….> SQL语句1 <if test=“条件表达式”& ...

  8. Java数据结构——树、二叉树的理论知识汇总

    通用树的理论知识 一.树的定义 由一个或多个(n>=0)节点组成的有限集合T,有且仅有一个节点称为根(root),当n>1时,其7余的节点为m(m>=0)个互不相交的有限集合T1,T ...

  9. 超市管理系统C语言

    登录系统 # include <stdio.h> //头文件 # include <string.h> //字符串头文件 # include <stdlib.h> ...

  10. js实现树级递归,通过js生成tree树形菜单(递归算法)

    方法封装: /** * 数据转换为树形(递归),示例:toTreeByRecursion(source, 'id', 'parentId', null, 'children') * @param {A ...