熔斷器 Hystrix 原始碼解析 —— 命令執行(一)之正常執行邏輯

芋道原始碼_以德服人_不服就幹發表於2017-12-02

摘要: 原創出處 http://www.iocoder.cn/Hystrix/command-execute-first-run/ 「芋道原始碼」歡迎轉載,保留摘要,謝謝!

本文主要基於 Hystrix 1.5.X 版本


熔斷器 Hystrix 原始碼解析 —— 命令執行(一)之正常執行邏輯

???關注**微信公眾號:【芋道原始碼】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有原始碼分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文註釋原始碼 GitHub 地址
  3. 您對於原始碼的疑問每條留言將得到認真回覆。甚至不知道如何讀原始碼也可以請教噢
  4. 新的原始碼解析文章實時收到通知。每週更新一篇左右
  5. 認真的原始碼交流微信群。
  6. 掘金 Java 群 :217878901

1. 概述

本文主要分享 Hystrix 命令執行(一)之正常執行邏輯

建議 :對 RxJava 已經有一定的瞭解的基礎上閱讀本文。

Hystrix 執行命令整體流程如下圖:

FROM 《【翻譯】Hystrix文件-實現原理》「流程圖」

熔斷器 Hystrix 原始碼解析 —— 命令執行(一)之正常執行邏輯

  • 框 :Hystrix 命令執行的過程。
  • 圈 :本文分享的部分 —— 正常執行邏輯。

推薦 Spring Cloud 書籍

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 裡提供了兩種執行隔離策略

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: }
複製程式碼

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 行 :設定 commandStateUSER_CODE_EXECUTED 。若設定失敗,呼叫 Observable#error(Exception) 方法返回 Observable 。
    • 第 17 行 :TODO 【2002】【metrics】
    • 第 20 至 24 行 :TODO 【2009】【執行超時】
    • 第 27 行 :設定 threadStateThreadState.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 行 :設定 threadStateThreadState.STARTED 失敗,執行命令此時已經被取消,呼叫 Observable#empty() 方法返回 Observable 。
    • 第 58 至 68 行 :呼叫 Observable#doOnTerminate(...) 方法,新增 Action0 。#handleThreadEnd(...) 方法,點選 連結 檢視。
    • 第 69 至 79 行 :呼叫 Observable#doOnUnsubscribe(...) 方法,新增 Action0 。
    • 第 80 至 85 行 :呼叫 Observable#subscribeOn(Scheduler) 方法,指定 Observable 自身在哪個排程器上執行。
  • 第 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();
    複製程式碼
  • 第 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】。
  • 第 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
}
複製程式碼

狀態變遷如下圖 :

熔斷器 Hystrix 原始碼解析 —— 命令執行(一)之正常執行邏輯

9. ThreadState

com.netflix.hystrix.AbstractCommand.ThreadState ,執行緒狀態,程式碼如下 :

protected enum ThreadState {
   NOT_USING_THREAD, STARTED, UNSUBSCRIBED, TERMINAL
}
複製程式碼

狀態變遷如下圖 :

熔斷器 Hystrix 原始碼解析 —— 命令執行(一)之正常執行邏輯

666. 彩蛋

對 Hystrix 和 RxJava 慢慢更有感覺了。

柳暗花明又一村。

繼續加油!

胖友,分享一波朋友圈可好!

相關文章