Hystrix解析(三)

executeCommandAndObserve

  • 定义不同的回调,doOnNext、doOnCompleted、onErrorResumeNext、doOnEach。
  • 调用executeCommandWithSpecifiedIsolation获得执行命令的Observable
  • 若执行命令超时特性开启,调用 Observable.lift 方法实现执行命令超时功能
private Observable<R> executeCommandAndObserve(final AbstractCommand<R> _cmd) {
    final HystrixRequestContext currentRequestContext = HystrixRequestContext.getContextForCurrentThread();

    //Action和Func都是定义的一个动作,Action是无返回值,Func是有返回值
    // doOnNext中的回调。即命令执行之前执行的操作
    final Action1<R> markEmits = new Action1<R>() //...
        
    // doOnCompleted中的回调。命令执行完毕后执行的操作
    final Action0 markOnCompleted = new Action0() //...
        
    // onErrorResumeNext中的回调。命令执行失败后的回退逻辑
    final Func1<Throwable, Observable<R>> handleFallback = new Func1<Throwable, Observable<R>>() //...

    // doOnEach中的回调。`Observable`每发射一个数据都会执行这个回调,设置请求上下文
    final Action1<Notification<? super R>> setRequestContext = new Action1<Notification<? super R>>() //...

    Observable<R> execution;
    if (properties.executionTimeoutEnabled().get()) {
        execution = executeCommandWithSpecifiedIsolation(_cmd)
            .lift(new HystrixObservableTimeoutOperator<R>(_cmd));
    } else {
        execution = executeCommandWithSpecifiedIsolation(_cmd);
    }

    return execution.doOnNext(markEmits)
        .doOnCompleted(markOnCompleted)
        .onErrorResumeNext(handleFallback)
        .doOnEach(setRequestContext);
}

executeCommandWithSpecifiedIsolation

这个方法首先是根据当前不同的资源隔离策略执行不同的逻辑,THREAD、SEMAPHORE。

private Observable<R> executeCommandWithSpecifiedIsolation(final AbstractCommand<R> _cmd) {
    if (properties.executionIsolationStrategy().get() == ExecutionIsolationStrategy.THREAD) {
        //...
    } else {
       //...
                try {
                    executionHook.onRunStart(_cmd);
                    executionHook.onExecutionStart(_cmd);
                    return getUserExecutionObservable(_cmd);  //the getUserExecutionObservable method already wraps sync exceptions, so this shouldn't throw
                } catch (Throwable ex) {
                    //If the above hooks throw, then use that as the result of the run method
                    return Observable.error(ex);
                }
            }
        });
    }
}

getUserExecutionObservable

调用 getExecutionObservable 方法创建 命令执行Observable 。 getExecutionObservable 方法是个抽象方法, HystrixCommand 实现了该方法。

private Observable<R> getUserExecutionObservable(final AbstractCommand<R> _cmd) {
    Observable<R> userObservable;

    try {
        userObservable = getExecutionObservable();
    } catch (Throwable ex) {
        // the run() method is a user provided implementation so can throw instead of using Observable.onError
        // so we catch it here and turn it into Observable.error
        userObservable = Observable.error(ex);
    }

    return userObservable
        .lift(new ExecutionHookApplication(_cmd))
        .lift(new DeprecatedOnRunHookApplication(_cmd));
}

HystrixCommand

调用 HystrixCommand.getExecutionObservable 方法创建命令执行Observable这里最终调用的是run方法,通过Observable.just, just是RxJava中的一个操作符,它可以接受一个或者多个参数来创建一个Observable对象。
而这个run()方法是一个抽象方法,在HystrixCommand中并没有实现,而是在子类中实现,而此时传递的cmd=GenricCommand正好实现了HystrixCommand,重写了run方法

final protected Observable<R> getExecutionObservable() {
    return Observable.defer(new Func0<Observable<R>>() {
        @Override
        public Observable<R> call() {
            try {
                return Observable.just(run());
            } catch (Throwable ex) {
                return Observable.error(ex);
            }
        }
    }).doOnSubscribe(new Action0() {
        @Override
        public void call() {
            // Save thread on which we get subscribed so that we can interrupt it later if needed
            executionThread.set(Thread.currentThread());
        }
    });
}

GenericCommand.run

这里的实现和我们前面自定义的 HystrixCommandService 实现是一样的,同样是集成HystrixCommand,重写run方法。这里也是如此。

  • 首先调用 getCommandAction() 方法获取 CommandAction。
  • 然后调用 MethodExecutionAction.execute 方法,传入 ExecutionType 参数。
protected Object run() throws Exception {
    LOGGER.debug("execute command: {}", getCommandKey().name());
    return process(new Action() {
        @Override
        Object execute() {
            return getCommandAction().execute(getExecutionType());
        }
    });
}

关系图

posted @ 2020-12-15 11:34  snail灬  阅读(173)  评论(0编辑  收藏  举报