类分析图:
测试用例:
@RestController
public class DeptController {
@RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET)
@HystrixCommand(fallbackMethod = "processHystrix_Get")
public Dept get(@PathVariable("id") Long id) {
System.out.println("请求的ID为:"+id);
throw new RuntimeException("该ID:" + id + "没有没有对应的信息");
}
public Dept processHystrix_Get(@PathVariable("id") Long id) {
return new Dept().setDeptno(id).setDname("该ID:" + id + "没有没有对应的信息,null--@HystrixCommand")
.setDb_source("no this database in MySQL");
}
}
接上一篇博客:继续执行
result = CommandExecutor.execute(invokable, executionType, metaHolder);
public static Object execute(HystrixInvokable invokable, ExecutionType executionType, MetaHolder metaHolder) throws RuntimeException {
Validate.notNull(invokable);
Validate.notNull(metaHolder);
//从上边的请求可以知道executionType为 SYNCHRONOUS异步请求
switch (executionType) {
case SYNCHRONOUS: {
return castToExecutable(invokable, executionType).execute();
}
case ASYNCHRONOUS: {
HystrixExecutable executable = castToExecutable(invokable, executionType);
if (metaHolder.hasFallbackMethodCommand()
&& ExecutionType.ASYNCHRONOUS == metaHolder.getFallbackExecutionType()) {
return new FutureDecorator(executable.queue());
}
return executable.queue();
}
case OBSERVABLE: {
HystrixObservable observable = castToObservable(invokable);
return ObservableExecutionMode.EAGER == metaHolder.getObservableExecutionMode() ? observable.observe() : observable.toObservable();
}
default:
throw new RuntimeException("unsupported execution type: " + executionType);
}
}
castToExecutable(invokable, executionType).execute();
private static HystrixExecutable castToExecutable(HystrixInvokable invokable, ExecutionType executionType) {
if (invokable instanceof HystrixExecutable) {
return (HystrixExecutable) invokable;//通过上一篇博客我们知道invokable(GenericCommand.class)
}
}
execute()方法拓展以及介绍:
方法 | ||
---|---|---|
#execute() | 同步调用,返回直接结果,; | |
#queue() | 异步调用,返回 java.util.concurrent.Future | |
#observe() | 异步调用,返回 rx.Observable 。向 Observable 注册 rx.Subscriber 处理结果 | |
#toObservable() | 未调用,返回 rx.Observable 。向 Observable 注册 rx.Subscriber 处理结果 |
execute()直接调用返回结果。内部执行方法
queue().get();。下面部分代码将省略
public R execute() {
try {
return queue().get();
} catch (Exception e) {
throw Exceptions.sneakyThrow(decomposeException(e));
}
}
public Future<R> queue() {
/*
*
*/
final Future<R> delegate = toObservable().toBlocking().toFuture();
final Future<R> f = new Future<R>() {
@Override
public boolean isDone() {
return delegate.isDone();
}
@Override
public R get() throws InterruptedException, ExecutionException {
return delegate.get();
}
/* special handling of error states that throw immediately */
if (f.isDone()) {
try {
f.get();
return f;
} catch (Exception e) {
}
}
return f;
}
toObservable().toBlocking().toFuture():重点分析
引用自http://www.iocoder.cn/Hystrix/command-execute-result-cache/ 芋道源码
1:public Observable<R> toObservable() {
2: final AbstractCommand<R> _cmd = this;
3:
4: //doOnCompleted handler already did all of the SUCCESS work
5: //doOnError handler already did all of the FAILURE/TIMEOUT/REJECTION/BAD_REQUEST work
6: final Action0 terminateCommandCleanup = new Action0() {} // ... 省略
7:
8: //mark the command as CANCELLED and store the latency (in addition to standard cleanup)
9: final Action0 unsubscribeCommandCleanup = new Action0() {} // ... 省略
10:
11: final Func0<Observable<R>> applyHystrixSemantics = new Func0<Observable<R>>() {
12: @Override
13: public Observable<R> call() {
14: if (commandState.get().equals(CommandState.UNSUBSCRIBED)) {
15: return Observable.never();
16: }
17: return applyHystrixSemantics(_cmd);//详见下一节:applyHystrixSemantics分析
18: }
19: };
20:
21: final Func1<R, R> wrapWithAllOnNextHooks = new Func1<R, R>() {} // ... 省略
22:
23: final Action0 fireOnCompletedHook = new Action0() {} // ... 省略
24:
25: return Observable.defer(new Func0<Observable<R>>() {
26: @Override
27: public Observable<R> call() {
28: // 每次调用execute方法都需要创建一个新的Command实例,因为每个实例都有自己的状态
29: if (!commandState.compareAndSet(CommandState.NOT_STARTED, CommandState.OBSERVABLE_CHAIN_CREATED)) {
32: throw new HystrixRuntimeException(FailureType.BAD_REQUEST_EXCEPTION, _cmd.getClass(), getLogMessagePrefix() + " command executed multiple times - this is not permitted.", ex, null);
33: }
35: // 命令开始时间戳
36: commandStartTimestamp = System.currentTimeMillis();
38: //【打印日志】
39: if (properties.requestLogEnabled().get()) {
40: // log this command execution regardless of what happened
41: if (currentRequestLog != null) {
42: currentRequestLog.addExecutedCommand(_cmd);
43: }
44: }
46: // 缓存开关、缓存KEY
47: final boolean requestCacheEnabled = isRequestCachingEnabled();
48: final String cacheKey = getCacheKey();
49:
50: // 优先从缓存中获取
51: /* try from cache first */
52: if (requestCacheEnabled) {
53: HystrixCommandResponseFromCache<R> fromCache = (HystrixCommandResponseFromCache<R>) requestCache.get(cacheKey);
54: if (fromCache != null) {
55: isResponseFromCache = true; // 标记 从缓存中结果
56: return handleRequestCacheHitAndEmitValues(fromCache, _cmd);
57: }
58: }
60: // 获得 执行命令Observable
61: Observable<R> hystrixObservable =
62: Observable.defer(applyHystrixSemantics)
63: .map(wrapWithAllOnNextHooks);
65: // 获得 缓存Observable
66: Observable<R> afterCache;
67: // 当缓存特性开启,并且缓存未命中时,创建【订阅了执行命令的 Observable】的 HystrixCommandResponseFromCache 。put in cache
68: if (requestCacheEnabled && cacheKey != null) {
69: //创建 HystrixCommandResponseFromCache ,并添加到 requestCache
70: HystrixCachedObservable<R> toCache = HystrixCachedObservable.from(hystrixObservable, _cmd);//详见提示一
71: // 哟,HystrixRequestCache#putIfAbsent(...)
方法,多个线程添加时,只有一个线程添加成功。putIfAbsent 如果传入key对应的value已经存在,就返回存在的value,不进行替换。如果不存在,就添加key和value,返回null
72: HystrixCommandResponseFromCache<R> fromCache = (HystrixCommandResponseFromCache<R>) requestCache.putIfAbsent(cacheKey, toCache);
73: if (fromCache != null) {
74: //说明有其他线程在此之前执行了上面的操作
75: toCache.unsubscribe();
76: isResponseFromCache = true; // 标记 从缓存中结果
77: return handleRequestCacheHitAndEmitValues(fromCache, _cmd);
78: } else { // 添加成功
//这个返回的Observale是HystrixCachedObservable.from执行后封装过的
80: afterCache = toCache.toObservable();
81: }
82: } else {
83: afterCache = hystrixObservable;
84: }
87: return afterCache
88: .doOnTerminate(terminateCommandCleanup) // perform cleanup once (either on normal terminal state (this line), or unsubscribe (next line))
89: .doOnUnsubscribe(unsubscribeCommandCleanup) // perform cleanup once
90: .doOnCompleted(fireOnCompletedHook);
91: }
92: });
93: }
提示一:对于开启缓存的会Observable会被ReplaySubject订阅。applyHystrixSemantics会直接执行。
HystrixCachedObservable
1: public class HystrixCachedObservable<R> {
2: /**
3: * 订阅
4: */
5: protected final Subscription originalSubscription;
6: /**
7: * 缓存 cachedObservable
8: */
9: protected final Observable<R> cachedObservable;
13: private volatile int outstandingSubscriptions = 0;
14: //private AtomicInteger outstandingSubscriptions2 = new AtomicInteger(0);
15:
16: protected HystrixCachedObservable(final Observable<R> originalObservable) {
17: ReplaySubject<R> replaySubject = ReplaySubject.create();
18: this.originalSubscription = originalObservable
19: .subscribe(replaySubject);
20:
21: this.cachedObservable = replaySubject
22: .doOnUnsubscribe(new Action0() {
23: @Override
24: public void call() {
25: outstandingSubscriptions--;
26: if (outstandingSubscriptions == 0) {
27: originalSubscription.unsubscribe();
28: }
29: }
30: })
31: .doOnSubscribe(new Action0() {
32: @Override
33: public void call() {
34: outstandingSubscriptions++;
35: }
36: });
37: }
第 17 至 19 行 :实际上,HystrixCachedObservable 不是一个 Observable 的子类,而是对传入的 Observable 封装 :使用 ReplaySubject 向传入的 Observable 发起订阅,通过 ReplaySubject 能够重放执行结果,从而实现缓存的功效。这里有几个卡到笔者的并且很有趣的点,我们一一道来 :从上文中,我们可以看到,传入的 originalObservable
为 hystrixObservable
执行命令 Observable 。在 Hystrix 里,提供了两种执行命令的隔离方式 :线程池( THREAD
) 和信号量( SEMAPHORE
)。
- 当使用
THREAD
隔离时,#subscribe(replaySubject)
调用完成时,实际命令并未开始执行(因为采用线程池的缘故,会将后续的执行逻辑封装为一个任务放到Rxjava中的Schedule中去异步执行),或者说,这是一个异步的执行命令的过程。那么,会不会影响返回执行结果呢?答案当然是不会,BlockingObservable 在得到执行完成才会结束阻塞,此时已经有执行结果。 -
当使用
SEMAPHORE
隔离时,#subscribe(replaySubject)
调用完成时,实际命令已经执行完成(如果采用信号量则由当前线程来执行),所以即使AbstractCommand#toObservavle(...)
的第 75 行 :调用HystrixCommandResponseFromCache#unsubscribe()
方法,也会浪费,重复执行命令。而对于THREAD
隔离的情况,通过取消订阅的方式,只会执行一次命令。当然,如果“恶搞”THREAD
隔离的情况,增加sleep
的调用如下,就能达到重复执行命令的效果。
HystrixCommandResponseFromCache
com.netflix.hystrix.HystrixCommandResponseFromCache
,是 HystrixCachedObservable 的子类。在父类的基础上,增加了对 AbstractCommand.executionResult
的关注。
HystrixCachedObservable#from(Observable, AbstractCommand)
方法,创建 HystrixCommandResponseFromCache 对象,点击 链接 查看。
HystrixCommandResponseFromCache#toObservableWithStateCopiedInto(...)
方法,点击 链接 查看。
- 通过
completionLogicRun
属性,保证#doOnError()
,#doOnCompleted()
,#doOnUnsubscribe()
方法有且只有一个方法执行具体逻辑。#doOnError()
,#doOnCompleted()
执行时,调用#commandCompleted()
方法,从缓存命令(HystrixCommandResponseFromCache.originalCommand
) 复制executionResult
属性给当前命令(commandToCopyStateInto
) 。#doOnUnsubscribe()
执行时,调用#commandUnsubscribed()
方法,使用当前命令(commandToCopyStateInto
)自己的executionResult
,不进行复制。