SpringCloud详解 第三章 服务容错保护 Hystrix(二)

本章节详细介绍 Hystrix 各接口和注解的使用方法

一、HystrixCommand

上文中我们通过Hystrix 中的核心注解 @HystrixCommand, 通过它创建了 HystrixCommand 的实现,同时利用 fallback 属性指定了服务降级的实现方法。然而这些还只是 Hystrix 使用的一 小部分,在实现 一 个大型分布式系统时,往往还需要更多高级的配置功能。 接下来我们将详细介绍 Hystrix 各接口和注解的使用方法。创建请求命令:

  Hystrix 命令就是我们之前所说的 HystrixCommand, 它用来封装具体的依赖服务调用逻辑。我们可以通过继承的方式来实现, 比如:

public class HelloCommand extends HystrixCommand<String> {

    private RestTemplate restTemplate;

    private HashMap map;

    public HelloCommand(RestTemplate restTemplate, HashMap paramMap) {
        super(com.netflix.hystrix.HystrixCommand.Setter.withGroupKey(
                HystrixCommandGroupKey.Factory.asKey("")).andCommandPropertiesDefaults(
                HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(5000)));
        this.restTemplate = restTemplate;
        this.map = paramMap;
    }

    @Override
    protected String run() {
        return restTemplate.getForObject("http://cloud-provider/hello?id={id}", String.class, map);
    }
  // 服务降级
    @Override
    protected String getFallback() {
        return "error-err";
    }
}

通过上面实现的HelloCommand , 我们既可以实现请求的同步执行也可以实现异步执行。除了传统的同步执行与异步执行之外, 我们还可以将 HystrixComrnand 通过Observable 来实现响应式执行方式。通过调用 observe()和toObservable ()方法可以返回 Observable 对象observe ()和toObservable ()虽然都返回了 Observable, 但是它们略有不同,前者返回的是一 个Hot Observable, 该命令会在 observe ()调用的时候立即执行, 当Observable 每次被订阅的时候会重放它的行为;而后者返回的是一 个Cold Observable,toObservable ()执行之后,命令不会被立即执行,只有当所有订阅者都订阅它之后才会执行。

//继承HystrixCommand的实现
@RequestMapping(value = "/helloCommand")
public String helloCommand(Long id) {
  HashMap map = new HashMap<>();
  map.put("id", id);
  //同步
  String result = new HelloCommand(restTemplate, map).execute();
  //异步
//        Future<String> result = new HelloCommand(restTemplate, map).queue();
        //响应式执行方式
//        Observable<String> hotObserve = new HelloCommand(restTemplate, map).observe();
//        Observable<String> coldObservable = new HelloCommand(restTemplate, map).toObservable();
  return result;
}

异步执行的时候, 可以通过对返回的 result 调用 get 方法来获取结果。另外, 也可以通过 上文@HystrixCommand 注解来更为优雅地实现 Hystrix 命令的定义,虽然 @HystrixCommand 注解可以非常优雅地定义 Hystrix 命令的实现, 但是如上定义的 get 方式只是同步执行的实现,若要实现异步执行则还需另外定义,比如:

//异步
@HystrixCommand(fallbackMethod = "getByidAsyncFailed")//熔断机制
@RequestMapping(value = "/getByidAsync")
public String getUserByidAsync(String id) {
        HashMap map = new HashMap<>();
        map.put("id", id);
        AsyncResult<String> asyncResult = new AsyncResult<String>() {
            @Override
            public String invoke() {
                return restTemplate.getForObject(REST_URL_PREFIX + "/hello?id={id}", String.class, map);
            }

            @Override
            public String get() {
                return invoke();
            }
        };
        return asyncResult.get();
}

二、HystrixObservableCommand

虽然 HystrixCornrnand 具备了 observe ()和toObservable() 的功能,但是它的实现有 一 定的局限性,它返回的 Observable 只能发射 一 次数据,所以 Hystrix 还提供了另外 一 个特殊命令封装 HystrixObservableCornrnand, 通过它实现的命令可以获取能发射多次的 Observable 。如果使用 HystrixObservableCornrnand 来实现命令封装,需要将命令的执行逻辑在construct 方法中重载,这样 Hystrix 才能将具体逻辑包装到 Observable 内,如下所示:

public class HelloObservableCommand extends HystrixObservableCommand<String> {
    private RestTemplate restTemplate;

    private HashMap map;

    public HelloObservableCommand(RestTemplate restTemplate, HashMap paramMap) {
        super(com.netflix.hystrix.HystrixObservableCommand.Setter.withGroupKey(
                HystrixCommandGroupKey.Factory.asKey("")).andCommandPropertiesDefaults(
                HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(5000)));
        this.restTemplate = restTemplate;
        this.map = paramMap;
    }

    @Override
    protected Observable<String> construct() {
        return Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> observer) {
                try {
                    if (!observer.isUnsubscribed()) {
                        String string = restTemplate.getForObject("http://cloud-provider/hello?id={id}", String.class, map);
                        observer.onNext(string);
                        observer.onCompleted();
                    }
                } catch (Exception e) {
                    observer.onError(e);
                }
            }
        });
    }
}

而对此的注解实现依然是使用 @HystrixCommand, 只是方法定义需要做 一 些变化,具体内容与 construct ()的实现类似,如下所示:

//HystrixObservableCommand
//EAGER 是该参数的模式值, 表示使用 observe ()执行方式。
@HystrixCommand(fallbackMethod = "getByidAsyncFailed", observableExecutionMode = ObservableExecutionMode.EAGER)
//    //表示使用 toObservable() 执行方式。
//    @HystrixCommand(fallbackMethod = "getByidAsyncFailed",observableExecutionMode = ObservableExecutionMode.LAZY)
@RequestMapping(value = "/helloHystrixObservableCommand")
public Observable<String> helloHystrixObservableCommand(String id) {
        HashMap map = new HashMap<>();
        map.put("id", id);
        return Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> observer) {
                try {
                    if (!observer.isUnsubscribed()) {
                        String string = restTemplate.getForObject("http://cloud-provider/hello?id={id}", String.class, map);
                        observer.onNext(string);
                        observer.onCompleted();
                    }
                } catch (Exception e) {
                    observer.onError(e);
                }
            }
        });
}

 

posted @ 2020-10-02 17:57  跃小云  阅读(92)  评论(0编辑  收藏  举报