接上一篇,最近加班過於嚴重,沒有時間繼續學習,抽了一些零碎的時間,認真的閱讀了一下源碼和官網的文檔,記錄一下自己對feign和hystrix的理解。
之前先把feign和hystrix分解的來學,明白了request是如何構造的,請求時如何發送的,接下來整體的進行學習。水平有限,有些理解會有偏差,再深入下去很多概念都不理解了,下一章開始繼續學習後面的zuul,把整體的springcloud學完後,再回頭深入研究這裏和eurake源碼。
hystrix把每一次請求都封裝成了一個commond對象,實際運行在單獨的線程中,也就是設計模式中的命令模式。這也是爲什麼之前調試源碼時一直找不到執行順序的原因。
springcloud中分別有HystrixCommond和HystrixObservableCommand兩個不同的命令對象。
HystrixCommond執行execute()方法,HystrixObservableCommand執行observe()方法。
兩個命令的區別在於HystrixCommond的命令邏輯在run方法,HystrixObservableCommand的命令邏輯在construct方法中。
HystrixCommond可以支持同步和異步兩種方法,HystrixObservableCommand只支持異步方式。
詳細的可以參考stackoverflow的回答:兩者的區別。
在springcloud中,使用的是HystrixCommond,之前講過實際去執行請求的是HystrixInvocationHandler類,可以看到invoke的核心邏輯:
HystrixCommand<Object> hystrixCommand = new HystrixCommand<Object>(setterMethodMap.get(method)) {
@Override
protected Object run() throws Exception {
try {
return HystrixInvocationHandler.this.dispatch.get(method).invoke(args);
} catch (Exception e) {
throw e;
} catch (Throwable t) {
throw (Error) t;
}
}
@Override
protected Object getFallback() {
if (fallbackFactory == null) {
return super.getFallback();
}
try {
Object fallback = fallbackFactory.create(getExecutionException());
Object result = fallbackMethodMap.get(method).invoke(fallback, args);
if (isReturnsHystrixCommand(method)) {
return ((HystrixCommand) result).execute();
} else if (isReturnsObservable(method)) {
// Create a cold Observable
return ((Observable) result).toBlocking().first();
} else if (isReturnsSingle(method)) {
// Create a cold Observable as a Single
return ((Single) result).toObservable().toBlocking().first();
} else if (isReturnsCompletable(method)) {
((Completable) result).await();
return null;
} else {
return result;
}
} catch (IllegalAccessException e) {
// shouldn't happen as method is public due to being an interface
throw new AssertionError(e);
} catch (InvocationTargetException e) {
// Exceptions on fallback are tossed by Hystrix
throw new AssertionError(e.getCause());
}
}
};
重寫了run和getFallback方法,run方法就是命令的執行邏輯,getFallback就是出現異常或者開啓熔斷時的降級處理方法。
dispatch中的key就是待執行的feign遠程調用方法,value就是我們之前學到的SynchronousMethodHandler對象,包括了target好額構造的request。
構造完HystrixCommond對象後,調用execute方法:
public R execute() {
try {
return queue().get();
} catch (Exception e) {
throw decomposeException(e);
}
}
final Observable<R> o = toObservable();
final Future<R> f = o.toBlocking().toFuture();
queue實際上是異步的,看toObservable()方法的解釋:
Used for asynchronous execution of command with a callback by subscribing to the {@link Observable}.
這裏實際上就是觀察者模式,只有當有訂閱了該對象時纔會執行,toObservable()方法的主要邏輯:
首先查詢緩存:
if (requestCacheEnabled) {
Observable<R> fromCache = requestCache.get(getCacheKey());
if (fromCache != null) {
/* mark that we received this response from cache */
metrics.markResponseFromCache();
isExecutionComplete.set(true);
try {
executionHook.onCacheHit(this);
} catch (Throwable hookEx) {
logger.warn("Error calling HystrixCommandExecutionHook.onCacheHit", hookEx);
}
return new CachedObservableResponse<R>((CachedObservableOriginal<R>) fromCache, this);
}
}
緩存中沒有則創建一個被觀察者對象,等待有訂閱時執行命令,主要就是構造對象,重寫call方法,其中會有一些記錄統計信息的操作。
Observable<R> o = Observable.create(new OnSubscribe<R>() ;
然後根據需求再把對象緩存。
創建了被觀察對象之後,接下來就是訂閱該對象,就可以執行方法,實現一個假的同步方法了。
實際上執行的邏輯就在toFuture中,至此,hystrix就利用異步的方法僞造了一個同步執行的邏輯。
接着看一下當遠程的方法拋異常時,是如何進入fallback的。
首先又回到了之前學過的SynchronousMethodHandler,這裏是真正進行請求和解析返回的地方。
當請求返回異常時,
throw errorDecoder.decode(metadata.configKey(), response);
拋出該異常,在HystrixCommond的run方法中捕獲該異常後直接拋出
後進入:
final protected Observable<R> getFallbackObservable() {
return Observable.create(new OnSubscribe<R>() {
@Override
public void call(Subscriber<? super R> s) {
try {
s.onNext(getFallback());
s.onCompleted();
} catch (Throwable e) {
s.onError(e);
}
}
});
}
進入到了上面我們重寫的getFallBack中,
Object fallback = fallbackFactory.create(getExecutionException());
Object result = fallbackMethodMap.get(method).invoke(fallback, args)
下一篇不再研究這裏的源碼了,超出能力範圍太多,先學習zuul,返回來再繼續弄透。