摘要: 原創出處 http://www.iocoder.cn/Hystrix/command-execute-first-run/ 「芋道原始碼」歡迎轉載,保留摘要,謝謝!
本文主要基於 Hystrix 1.5.X 版本
- 1. 概述
- 2. #applyHystrixSemantics(...)
- 3. TryableSemaphore
- 4. #executeCommandAndObserve(...)
- 5. #executeCommandWithSpecifiedIsolation(...)
- 6. #getUserExecutionObservable(...)
- 7. #getExecutionObservable()
- 8. CommandState
- 9. ThreadState
- 666. 彩蛋
???關注**微信公眾號:【芋道原始碼】**有福利:
- RocketMQ / MyCAT / Sharding-JDBC 所有原始碼分析文章列表
- RocketMQ / MyCAT / Sharding-JDBC 中文註釋原始碼 GitHub 地址
- 您對於原始碼的疑問每條留言都將得到認真回覆。甚至不知道如何讀原始碼也可以請教噢。
- 新的原始碼解析文章實時收到通知。每週更新一篇左右。
- 認真的原始碼交流微信群。
- 掘金 Java 群 :217878901
1. 概述
本文主要分享 Hystrix 命令執行(一)之正常執行邏輯。
建議 :對 RxJava 已經有一定的瞭解的基礎上閱讀本文。
Hystrix 執行命令整體流程如下圖:
- 紅框 :Hystrix 命令執行的過程。
- 藍圈 :本文分享的部分 —— 正常執行邏輯。
推薦 Spring Cloud 書籍:
- 請支援正版。下載盜版,等於主動編寫低階 BUG 。
- 程式猿DD —— 《Spring Cloud微服務實戰》
- 周立 —— 《Spring Cloud與Docker微服務架構實戰》
- 兩書齊買,京東包郵。
2. #applyHystrixSemantics(...)
在 《Hystrix 原始碼解析 —— 執行結果快取》 裡,我們看到 #toObservable()
方法裡的第 11 至 19 行,當快取特性未開啟,或者快取未命中時,使用 applyHystrixSemantics
傳入 Observable#defer(...)
方法,宣告執行命令的 Observable。
建立 applyHystrixSemantics
變數,程式碼如下 :
// `AbstractCommand#toObservable()` 方法
1: final Func0<Observable<R>> applyHystrixSemantics = new Func0<Observable<R>>() {
2: @Override
3: public Observable<R> call() {
4: // commandState 處於 UNSUBSCRIBED 時,不執行命令
5: if (commandState.get().equals(CommandState.UNSUBSCRIBED)) {
6: return Observable.never();
7: }
8: // 獲得 執行Observable
9: return applyHystrixSemantics(_cmd);
10: }
11: };
複製程式碼
- 第 5 至 7 行 :當
commandState
處於UNSUBSCRIBED
時,不執行命令。 - 第 9 行 :呼叫
#applyHystrixSemantics(...)
方法,獲得執行 Observable 。
#applyHystrixSemantics(...)
方法,程式碼如下 :
1: private Observable<R> applyHystrixSemantics(final AbstractCommand<R> _cmd) {
2: // TODO 【2003】【HOOK】
3: // mark that we're starting execution on the ExecutionHook
4: // if this hook throws an exception, then a fast-fail occurs with no fallback. No state is left inconsistent
5: executionHook.onStart(_cmd);
6:
7: /* determine if we're allowed to execute */
8: if (circuitBreaker.attemptExecution()) {
9: // 獲得 訊號量
10: final TryableSemaphore executionSemaphore = getExecutionSemaphore();
11:
12: // 訊號量釋放Action
13: final AtomicBoolean semaphoreHasBeenReleased = new AtomicBoolean(false);
14: final Action0 singleSemaphoreRelease = new Action0() {
15: @Override
16: public void call() {
17: if (semaphoreHasBeenReleased.compareAndSet(false, true)) {
18: executionSemaphore.release();
19: }
20: }
21: };
22:
23: // TODO 【2011】【Hystrix 事件機制】
24: final Action1<Throwable> markExceptionThrown = new Action1<Throwable>() {
25: @Override
26: public void call(Throwable t) {
27: eventNotifier.markEvent(HystrixEventType.EXCEPTION_THROWN, commandKey);
28: }
29: };
30:
31: // 訊號量 獲得
32: if (executionSemaphore.tryAcquire()) {
33: try {
34: // 標記 executionResult 呼叫開始時間
35: /* used to track userThreadExecutionTime */
36: executionResult = executionResult.setInvocationStartTime(System.currentTimeMillis());
37:
38: // 獲得 執行Observable
39: return executeCommandAndObserve(_cmd)
40: .doOnError(markExceptionThrown)
41: .doOnTerminate(singleSemaphoreRelease)
42: .doOnUnsubscribe(singleSemaphoreRelease);
43: } catch (RuntimeException e) {
44: return Observable.error(e);
45: }
46: } else {
47: return handleSemaphoreRejectionViaFallback();
48: }
49: } else {
50: return handleShortCircuitViaFallback();
51: }
52: }
複製程式碼
- 第 5 行 :TODO 【2003】【HOOK】
- 第 8 行 :TODO 【2012】【鏈路健康度】
- 第 10 行 :呼叫
#getExecutionSemaphore()
方法,獲得訊號量( TryableSemaphore )物件,在 「3. TryableSemaphore」 詳細解析。 - 第 13 至 21 行 :訊號量釋放 Action ,用於下面【執行命令 Observable】的
#doOnTerminate(Action)
和#doOnUnsubscribe(Action)
方法( 見第 41 至 42 行 )。 - 第 24 至 29 行 :TODO 【2011】【Hystrix 事件機制】
- 第 32 行 :呼叫
TryableSemaphore#tryAcquire()
方法,訊號量( TryableSemaphore )使用成功,在 「3. TryableSemaphore」 詳細解析。 - 第 36 行 :標記
executionResult
的呼叫開始時間。 - 第 39 行 :呼叫
#executeCommandAndObserve()
方法,獲得【執行命令 Observable】。在 「4. #executeCommandAndObserve(...)」 詳細解析。 - 第 43 至 45 行 :若發生異常,呼叫
Observable#error(Exception)
方法返回 Observable 。 - 第 46 至 48 行 :訊號量( TryableSemaphore )使用失敗,呼叫
#handleSemaphoreRejectionViaFallback()
方法,處理訊號量拒絕的失敗回退邏輯,在 《Hystrix 原始碼解析 —— 命令執行(四)之失敗回退邏輯》 詳細解析。 - 第 49 至 51 行 :鏈路處於熔斷狀態,呼叫
#handleShortCircuitViaFallback()
方法,處理鏈路熔斷的失敗回退邏輯,在 《Hystrix 原始碼解析 —— 命令執行(四)之失敗回退邏輯》 詳細解析。
3. TryableSemaphore
com.netflix.hystrix.AbstractCommand.TryableSemaphore
,Hystrix 定義的訊號量介面。程式碼如下 :
interface TryableSemaphore {
boolean tryAcquire();
void release();
int getNumberOfPermitsUsed();
}
複製程式碼
- 從 API 上,Java 自帶的
java.util.concurrent.Semaphore
都能滿足,為什麼不使用它呢?繼續一起往下看。
TryableSemaphore 共有兩個子類實現 :
- TryableSemaphoreNoOp
- TryableSemaphoreActual
3.1 TryableSemaphoreNoOp
com.netflix.hystrix.AbstractCommand.TryableSemaphoreNoOp
,無操作的訊號量。程式碼如下 :
/* package */static class TryableSemaphoreNoOp implements TryableSemaphore {
public static final TryableSemaphore DEFAULT = new TryableSemaphoreNoOp();
@Override
public boolean tryAcquire() {
return true;
}
@Override
public void release() {
}
@Override
public int getNumberOfPermitsUsed() {
return 0;
}
}
複製程式碼
- 從實現上看,
#tryAcquire()
方法,每次都返回的是true
;#release()
方法,無任何操作。這個是為什麼?在 Hystrix 裡提供了兩種執行隔離策略 :Thread
,該方式不使用訊號量,因此使用 TryableSemaphoreNoOp ,這樣每次呼叫#tryAcquire()
都能返回true
。在 《Hystrix 原始碼解析 —— 命令執行(二)之執行隔離策略》 詳細解析該方式。Semaphore
,該方式使用訊號量,因此使用 TryableSemaphoreActual ,這樣每次呼叫#tryAcquire()
根據情況返回true / false
。在 「3.2 TryableSemaphoreActual」 詳細解析。
3.2 TryableSemaphoreActual
com.netflix.hystrix.AbstractCommand.TryableSemaphoreActual
,真正的的訊號量實現。不過實際上,TryableSemaphoreActual 更加像一個計數器。程式碼如下 :
/* package */static class TryableSemaphoreActual implements TryableSemaphore {
protected final HystrixProperty<Integer> numberOfPermits;
private final AtomicInteger count = new AtomicInteger(0);
public TryableSemaphoreActual(HystrixProperty<Integer> numberOfPermits) {
this.numberOfPermits = numberOfPermits;
}
@Override
public boolean tryAcquire() {
int currentCount = count.incrementAndGet();
if (currentCount > numberOfPermits.get()) {
count.decrementAndGet();
return false;
} else {
return true;
}
}
@Override
public void release() {
count.decrementAndGet();
}
@Override
public int getNumberOfPermitsUsed() {
return count.get();
}
}
複製程式碼
numberOfPermits
屬性,訊號量上限。com.netflix.hystrix.strategy.properties.HystrixProperty
是一個介面,當其使用類似com.netflix.hystrix.strategy.properties.archaius.IntegerDynamicProperty
動態屬性的實現時,可以實現動態調整訊號量的上限,這就是上文提到的為什麼不使用java.util.concurrent.Semaphore
的原因之一。count
屬性,訊號量使用數量。?,這是為什麼說 TryableSemaphoreActual 更加像一個計數器 的原因。- 另一個不使用
java.util.concurrent.Semaphore
的原因,TryableSemaphoreActual 無阻塞獲取訊號量的需求,使用 AtomicInteger 可以達到更輕量級的實現。
3.3 #getExecutionSemaphore()
呼叫 #getExecutionSemaphore()
方法,獲得訊號量物件,程式碼如下 :
/**
* 執行命令(正常執行)訊號量對映
* KEY :命令名 {@link #commandKey}
*/
/* each circuit has a semaphore to restrict concurrent fallback execution */
protected static final ConcurrentHashMap<String, TryableSemaphore> executionSemaphorePerCircuit = new ConcurrentHashMap<String, TryableSemaphore>();
protected TryableSemaphore getExecutionSemaphore() {
if (properties.executionIsolationStrategy().get() == ExecutionIsolationStrategy.SEMAPHORE) {
if (executionSemaphoreOverride == null) {
TryableSemaphore _s = executionSemaphorePerCircuit.get(commandKey.name());
if (_s == null) { // 不存在時,建立 TryableSemaphoreActual
// we didn't find one cache so setup
executionSemaphorePerCircuit.putIfAbsent(commandKey.name(), new TryableSemaphoreActual(properties.executionIsolationSemaphoreMaxConcurrentRequests()));
// assign whatever got set (this or another thread)
return executionSemaphorePerCircuit.get(commandKey.name());
} else {
return _s;
}
} else {
return executionSemaphoreOverride;
}
} else {
// return NoOp implementation since we're not using SEMAPHORE isolation
return TryableSemaphoreNoOp.DEFAULT;
}
}
複製程式碼
- 根據執行隔離策略不同獲取不同的訊號量實現 :
Thread
,該方式不使用訊號量,因此使用 TryableSemaphoreNoOp 。Semaphore
,該方式使用訊號量,因此使用 TryableSemaphoreActual 。- 相同的
commandKey
,使用相同的 TryableSemaphoreActual 。
- 相同的
4. #executeCommandAndObserve(...)
呼叫 #executeCommandAndObserve(...)
方法,獲得【執行命令 Observable】。程式碼如下 :
1: private Observable<R> executeCommandAndObserve(final AbstractCommand<R> _cmd) {
2: // TODO 【】
3: final HystrixRequestContext currentRequestContext = HystrixRequestContext.getContextForCurrentThread();
4:
5: // TODO 【2007】【executionResult】用途
6: final Action1<R> markEmits = new Action1<R>() {
7: @Override
8: public void call(R r) {
9: if (shouldOutputOnNextEvents()) {
10: executionResult = executionResult.addEvent(HystrixEventType.EMIT);
11: eventNotifier.markEvent(HystrixEventType.EMIT, commandKey);
12: }
13: if (commandIsScalar()) {
14: long latency = System.currentTimeMillis() - executionResult.getStartTimestamp();
15: eventNotifier.markEvent(HystrixEventType.SUCCESS, commandKey);
16: executionResult = executionResult.addEvent((int) latency, HystrixEventType.SUCCESS);
17: eventNotifier.markCommandExecution(getCommandKey(), properties.executionIsolationStrategy().get(), (int) latency, executionResult.getOrderedList());
18: circuitBreaker.markSuccess();
19: }
20: }
21: };
22:
23: // TODO 【2007】【executionResult】用途
24: final Action0 markOnCompleted = new Action0() {
25: @Override
26: public void call() {
27: if (!commandIsScalar()) {
28: long latency = System.currentTimeMillis() - executionResult.getStartTimestamp();
29: eventNotifier.markEvent(HystrixEventType.SUCCESS, commandKey);
30: executionResult = executionResult.addEvent((int) latency, HystrixEventType.SUCCESS);
31: eventNotifier.markCommandExecution(getCommandKey(), properties.executionIsolationStrategy().get(), (int) latency, executionResult.getOrderedList());
32: circuitBreaker.markSuccess();
33: }
34: }
35: };
36:
37: // 失敗回退邏輯 Func1
38: final Func1<Throwable, Observable<R>> handleFallback = new Func1<Throwable, Observable<R>>() {
39: @Override
40: public Observable<R> call(Throwable t) {
41: circuitBreaker.markNonSuccess();
42: Exception e = getExceptionFromThrowable(t);
43: executionResult = executionResult.setExecutionException(e);
44: if (e instanceof RejectedExecutionException) {
45: return handleThreadPoolRejectionViaFallback(e);
46: } else if (t instanceof HystrixTimeoutException) {
47: return handleTimeoutViaFallback();
48: } else if (t instanceof HystrixBadRequestException) {
49: return handleBadRequestByEmittingError(e);
50: } else {
51: /*
52: * Treat HystrixBadRequestException from ExecutionHook like a plain HystrixBadRequestException.
53: */
54: if (e instanceof HystrixBadRequestException) {
55: eventNotifier.markEvent(HystrixEventType.BAD_REQUEST, commandKey);
56: return Observable.error(e);
57: }
58:
59: return handleFailureViaFallback(e);
60: }
61: }
62: };
63:
64: // TODO 【2008】【請求快取】
65: final Action1<Notification<? super R>> setRequestContext = new Action1<Notification<? super R>>() {
66: @Override
67: public void call(Notification<? super R> rNotification) {
68: setRequestContextIfNeeded(currentRequestContext);
69: }
70: };
71:
72: Observable<R> execution;
73: if (properties.executionTimeoutEnabled().get()) {
74: execution = executeCommandWithSpecifiedIsolation(_cmd)
75: .lift(new HystrixObservableTimeoutOperator<R>(_cmd)); // 超時
76: } else {
77: execution = executeCommandWithSpecifiedIsolation(_cmd);
78: }
79:
80: return execution.doOnNext(markEmits)
81: .doOnCompleted(markOnCompleted)
82: .onErrorResumeNext(handleFallback)
83: .doOnEach(setRequestContext);
84: }
複製程式碼
- 第 3 行 :TODO 【2012】【請求上下文】
- 第 6 至 21 行 :TODO 【2007】【executionResult】用途
- 第 24 至 35 行 :TODO 【2007】【executionResult】用途
- 第 38 至 62 行 :失敗回退邏輯 Func1 ,在 《Hystrix 原始碼解析 —— 請求執行(四)之失敗回退邏輯》 詳細解析。
- 第 65 至 70 行 :TODO 【2012】【請求上下文】
- 第 72 至 78 行 :呼叫
#executeCommandWithSpecifiedIsolation(...)
方法,獲得【執行命令 Observable】,在 「5. #executeCommandWithSpecifiedIsolation(...)」 詳細解析。- 若執行命令超時特性開啟,呼叫
Observable#lift(HystrixObservableTimeoutOperator)
方法,實現執行命令超時功能。在 《Hystrix 原始碼解析 —— 命令執行(三)之執行超時》 詳細解析。
- 若執行命令超時特性開啟,呼叫
- 第 80 至 83 行 :返回【執行命令 Observable】。
5. #executeCommandWithSpecifiedIsolation(...)
呼叫 #executeCommandWithSpecifiedIsolation(...)
方法,獲得【執行命令 Observable】。程式碼如下 :
1: private Observable<R> executeCommandWithSpecifiedIsolation(final AbstractCommand<R> _cmd) {
2: if (properties.executionIsolationStrategy().get() == ExecutionIsolationStrategy.THREAD) {
3: // mark that we are executing in a thread (even if we end up being rejected we still were a THREAD execution and not SEMAPHORE)
4: return Observable.defer(new Func0<Observable<R>>() {
5: @Override
6: public Observable<R> call() {
7:
8: // 標記 executionResult 執行已發生
9: executionResult = executionResult.setExecutionOccurred();
10:
11: // 設定 commandState 為 USER_CODE_EXECUTED
12: if (!commandState.compareAndSet(CommandState.OBSERVABLE_CHAIN_CREATED, CommandState.USER_CODE_EXECUTED)) {
13: return Observable.error(new IllegalStateException("execution attempted while in state : " + commandState.get().name()));
14: }
15:
16: // TODO 【2002】【metrics】
17: metrics.markCommandStart(commandKey, threadPoolKey, ExecutionIsolationStrategy.THREAD);
18:
19: // TODO 【2009】【執行超時】
20: if (isCommandTimedOut.get() == TimedOutStatus.TIMED_OUT) {
21: // the command timed out in the wrapping thread so we will return immediately
22: // and not increment any of the counters below or other such logic
23: return Observable.error(new RuntimeException("timed out before executing run()"));
24: }
25:
26: // 設定 執行緒狀態 為 ThreadState.STARTED
27: if (threadState.compareAndSet(ThreadState.NOT_USING_THREAD, ThreadState.STARTED)) {
28: // TODO 【2002】【metrics】
29: //we have not been unsubscribed, so should proceed
30: HystrixCounters.incrementGlobalConcurrentThreads();
31: threadPool.markThreadExecution();
32:
33: // TODO 【2010】【endCurrentThreadExecutingCommand】
34: // store the command that is being run
35: endCurrentThreadExecutingCommand = Hystrix.startCurrentThreadExecutingCommand(getCommandKey());
36:
37: // 標記 executionResult 使用執行緒執行
38: executionResult = executionResult.setExecutedInThread();
39: /**
40: * If any of these hooks throw an exception, then it appears as if the actual execution threw an error
41: */
42: try {
43: // TODO 【2003】【HOOK】
44: executionHook.onThreadStart(_cmd);
45: executionHook.onRunStart(_cmd);
46: executionHook.onExecutionStart(_cmd);
47:
48: // 獲得 執行Observable
49: return getUserExecutionObservable(_cmd);
50: } catch (Throwable ex) {
51: return Observable.error(ex);
52: }
53: } else {
54: //command has already been unsubscribed, so return immediately
55: return Observable.empty();
56: }
57: }
58: }).doOnTerminate(new Action0() {
59: @Override
60: public void call() {
61: if (threadState.compareAndSet(ThreadState.STARTED, ThreadState.TERMINAL)) {
62: handleThreadEnd(_cmd);
63: }
64: if (threadState.compareAndSet(ThreadState.NOT_USING_THREAD, ThreadState.TERMINAL)) {
65: //if it was never started and received terminal, then no need to clean up (I don't think this is possible)
66: }
67: //if it was unsubscribed, then other cleanup handled it
68: }
69: }).doOnUnsubscribe(new Action0() {
70: @Override
71: public void call() {
72: if (threadState.compareAndSet(ThreadState.STARTED, ThreadState.UNSUBSCRIBED)) {
73: handleThreadEnd(_cmd);
74: }
75: if (threadState.compareAndSet(ThreadState.NOT_USING_THREAD, ThreadState.UNSUBSCRIBED)) {
76: //if it was never started and was cancelled, then no need to clean up
77: }
78: //if it was terminal, then other cleanup handled it
79: }
80: }).subscribeOn(threadPool.getScheduler(new Func0<Boolean>() { // TODO 芋艿:Scheduler
81: @Override
82: public Boolean call() {
83: return properties.executionIsolationThreadInterruptOnTimeout().get() && _cmd.isCommandTimedOut.get() == TimedOutStatus.TIMED_OUT;
84: }
85: }));
86: } else {
87: return Observable.defer(new Func0<Observable<R>>() {
88: @Override
89: public Observable<R> call() {
90: // 標記 executionResult 執行已發生
91: executionResult = executionResult.setExecutionOccurred();
92:
93: // 設定 commandState 為 USER_CODE_EXECUTED
94: if (!commandState.compareAndSet(CommandState.OBSERVABLE_CHAIN_CREATED, CommandState.USER_CODE_EXECUTED)) {
95: return Observable.error(new IllegalStateException("execution attempted while in state : " + commandState.get().name()));
96: }
97:
98: // TODO 【2002】【metrics】
99: metrics.markCommandStart(commandKey, threadPoolKey, ExecutionIsolationStrategy.SEMAPHORE);
100:
101: // TODO 【2010】【endCurrentThreadExecutingCommand】
102: // semaphore isolated
103: // store the command that is being run
104: endCurrentThreadExecutingCommand = Hystrix.startCurrentThreadExecutingCommand(getCommandKey());
105: try {
106: // TODO 【2003】【HOOK】
107: executionHook.onRunStart(_cmd);
108: executionHook.onExecutionStart(_cmd);
109:
110: // 獲得 執行Observable
111: return getUserExecutionObservable(_cmd); //the getUserExecutionObservable method already wraps sync exceptions, so this shouldn't throw
112: } catch (Throwable ex) {
113: //If the above hooks throw, then use that as the result of the run method
114: return Observable.error(ex);
115: }
116: }
117: });
118: }
119: }
複製程式碼
-
根據執行隔離策略不同,建立不同的【執行命令 Observable】。仔細對比下,大體邏輯都是相同的,差別在於執行隔離策略為
Thread
時,使用 RxJava Scheduler 以及對執行緒的處理。 -
第 2 至 85 行 :執行隔離策略為
Thread
:- 第 9 行 :標記
executionResult
執行已發生。 - 第 12 至 14 行 :設定
commandState
為USER_CODE_EXECUTED
。若設定失敗,呼叫Observable#error(Exception)
方法返回 Observable 。 - 第 17 行 :TODO 【2002】【metrics】
- 第 20 至 24 行 :TODO 【2009】【執行超時】
- 第 27 行 :設定
threadState
為ThreadState.STARTED
成功。- 第 30 至 31 行 :TODO 【2002】【metrics】
- 第 35 行 :TODO 【2010】【endCurrentThreadExecutingCommand】
- 第 38 行 :標記
executionResult
使用執行緒執行。 - 第 44 至 46 行 :TODO 【2003】【HOOK】
- 第 49 行 :呼叫
#getUserExecutionObservable(...)
方法,建立【執行命令 Observable】。 - 第 50 至 52 行 :若發生異常,呼叫
Observable#error(Exception)
方法返回 Observable 。
- 第 53 至 56 行 :設定
threadState
為ThreadState.STARTED
失敗,執行命令此時已經被取消,呼叫Observable#empty()
方法返回 Observable 。 - 第 58 至 68 行 :呼叫
Observable#doOnTerminate(...)
方法,新增 Action0 。#handleThreadEnd(...)
方法,點選 連結 檢視。 - 第 69 至 79 行 :呼叫
Observable#doOnUnsubscribe(...)
方法,新增 Action0 。 - 第 80 至 85 行 :呼叫
Observable#subscribeOn(Scheduler)
方法,指定 Observable 自身在哪個排程器上執行。- RxJava Scheduler ,在 《RxJava 原始碼解析 —— Scheduler》 有詳細解析。
Observable#subscribeOn(Scheduler)
,在 《RxJava 原始碼解析 —— Observable#subscribeOn(Scheduler)》 有詳細解析。- 呼叫
ThreadPool#getScheduler(Func0<Boolean>)
方法,獲得 Hystrix 自定義實現的 RxJava Scheduler ,在 《Hystrix 原始碼解析 —— 命令執行(二)之執行隔離策略》 詳細解析。
- 第 9 行 :標記
-
第 86 至 118 行 :執行隔離策略為
SEMAPHORE
:- 第 91 行 :[ 與第 9 行相同 ]。
- 第 94 至 96 行 :[ 與第 12 至 14行相同 ]。
- 第 99 行 :[ 與第 17 行類似 ]。
- 第 104 行 :[ 與第 35 行相同 ]。
- 第 107 至 108 行 :[ 與第 45 至 46 行相同 ]。
- 第 111 行 :[ 與第 49 行相同 ]。
- 第 112 至 115 行 :[ 與第 50 至 52 行相同 ]。
6. #getUserExecutionObservable(...)
呼叫 #getUserExecutionObservable(...)
方法,建立【執行命令 Observable】。程式碼如下 :
1: private Observable<R> getUserExecutionObservable(final AbstractCommand<R> _cmd) {
2: Observable<R> userObservable;
3:
4: try {
5: userObservable = getExecutionObservable();
6: } catch (Throwable ex) {
7: // the run() method is a user provided implementation so can throw instead of using Observable.onError
8: // so we catch it here and turn it into Observable.error
9: userObservable = Observable.error(ex);
10: }
11:
12: return userObservable
13: .lift(new ExecutionHookApplication(_cmd)) // TODO 【2003】【HOOK】
14: .lift(new DeprecatedOnRunHookApplication(_cmd)); // 已廢棄
15: }
複製程式碼
-
第 5 行 :呼叫
#getExecutionObservable()
方法,建立【執行命令 Observable】。#getExecutionObservable()
是個抽象方法,程式碼如下 :protected abstract Observable<R> getExecutionObservable(); 複製程式碼
- HystrixCommand 實現了該方法,在 「7. #getExecutionObservable」 詳細解析。
-
第 6 至 10 行 :若發生異常,呼叫
Observable#error(Exception)
方法返回 Observable 。 -
第 12 至 14 行 :返回【執行命令 Observable】。
- 第 13 行 :TODO 【2003】【HOOK】
7. #getExecutionObservable()
呼叫 HystrixCommand#getExecutionObservable()
方法,建立【執行命令 Observable】。程式碼如下 :
1: @Override
2: final protected Observable<R> getExecutionObservable() {
3: return Observable.defer(new Func0<Observable<R>>() {
4: @Override
5: public Observable<R> call() {
6: try {
7: return Observable.just(run());
8: } catch (Throwable ex) {
9: return Observable.error(ex);
10: }
11: }
12: }).doOnSubscribe(new Action0() {
13: @Override
14: public void call() {
15: // 記錄 執行執行緒
16: // Save thread on which we get subscribed so that we can interrupt it later if needed
17: executionThread.set(Thread.currentThread());
18: }
19: });
20: }
21:
22: protected abstract R run() throws Exception;
複製程式碼
- 第 3 至 11 行 :呼叫
Observable#defer(Func0<Observable<R>)
方法,建立【執行命令 Observable】。- 第 7 行 :呼叫
#run()
方法,執行正常執邏輯。通過Observable#just(...)
方法,返回建立【執行命令 Observable】。
- 第 7 行 :呼叫
- 第 12 至 19 行 :呼叫
#doOnSubscribe(...)
方法,新增 Action 。該操作記錄執行執行緒(executionThread
) 。executionThread
用於HystrixCommand#queue()
方法,返回的 Future 結果,可以呼叫Future#cancel(Boolean)
方法,點選 連結 檢視該方法。 - 第 22 行 :
#run()
抽象方法,實現該方法,執行正常執邏輯。
8. CommandState
com.netflix.hystrix.AbstractCommand.CommandState
,命令狀態,程式碼如下 :
protected enum CommandState {
NOT_STARTED, OBSERVABLE_CHAIN_CREATED, USER_CODE_EXECUTED, UNSUBSCRIBED, TERMINAL
}
複製程式碼
狀態變遷如下圖 :
9. ThreadState
com.netflix.hystrix.AbstractCommand.ThreadState
,執行緒狀態,程式碼如下 :
protected enum ThreadState {
NOT_USING_THREAD, STARTED, UNSUBSCRIBED, TERMINAL
}
複製程式碼
狀態變遷如下圖 :
666. 彩蛋
對 Hystrix 和 RxJava 慢慢更有感覺了。
柳暗花明又一村。
繼續加油!
胖友,分享一波朋友圈可好!