接上一篇,最近加班过于严重,没有时间继续学习,抽了一些零碎的时间,认真的阅读了一下源码和官网的文档,记录一下自己对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,返回来再继续弄透。