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. golang ctrie demo

    下载ctrie: go get -t github.com/Workiva/go-datastructures/trie/ctrie 测试demo1: package main import ( &q ...

  2. 利用python爬取贝壳网租房信息

    最近准备换房子,在网站上寻找各种房源信息,看得眼花缭乱,于是想着能否将基本信息汇总起来便于查找,便用python将基本信息爬下来放到excel,这样一来就容易搜索了. 1. 利用lxml中的xpath ...

  3. 【译】Database Profiling with Visual Studio

    你是否在排查运行缓慢的 web 应用程序时怀疑是数据库层造成的?以前排查数据库层需要特定的工具,现在可以使用 Visual Studio 的 Performance Explorer 中的数据库分析工 ...

  4. 小白式DPDK搭建方法(附相关错误得处理方法)

    搭建环境:VM VM搭建参考其他博客 步骤一 点击虚拟机设置,添加两个网卡(我这里都是使用的都是桥接模式) 步骤二.从网上下载dpdk的压缩包: 命令:wget http://fast.dpdk.or ...

  5. Shell编程—控制脚本

    1处理信号 1.1信号表 编号 信号名称 缺省操作 解释 1 SIGHUP Terminate 挂起控制终端或进程 2 SIGINT Terminate 来自键盘的中断 3 SIGQUIT Dump ...

  6. Java GUI 图书管理系统

    01 概述 一款功能强大的图书馆管理系统,功能齐全,小白/大学生项目实训,学习的不二之选. 02 技术 此系统使用 java awt 实现.java.awt是一个软件包,包含用于创建用户界面和绘制图形 ...

  7. Java8中的Stream API

    本篇文章继续介绍Java 8的另一个新特性——Stream API.新增的Stream API与InputStream和OutputStream是完全不同的概念,Stream API是对Java中集合 ...

  8. vue学习笔记一

    vue 颠覆式的开发方式 解疑 为什么要学习vue? 降低项目的复杂度 就业需要 vue难不难? 特别简单 相比于React,vue有什么优势? 前端三大框架:Angular.React.Vue Vu ...

  9. 记录call、apply、bind的源码

    记录一下call.apply.bind的源码,然后从根本上明白其用法. 都知道call.apply与bind的用法,call(this,...arguments).apply(this,[argume ...

  10. 【BZOJ3453】XLkxc

    http://192.168.102.138/JudgeOnline/problem.php?id=3170 知识点:1.拉格朗日插值(多特殊函数相加) 2.这个式子看似非常复杂,然而只要明白这个式子 ...