SpringCloud - 服务容错保护组件Hystrix的使用详解2(创建请求命令)
二、创建请求命令
1,Hystrix 命令介绍
(1)Hystrix 命令就是我们前面说的 HystirxCommand,它用来封装具体的依赖服务调用逻辑。
- 通过其 execute() 方法和 queue() 方法可以分别实现请求的同步执行、异步执行。
- 除此之外还可以调用其 observe() 方法和 toObservable()方法返回 Observable 对象,从而实现响应式执行方式。
(2)我们除了可以通过继承 HystirxCommand 的方式实现 Hystrix 命令外,也可以通过 @HystrixCommand 注解更为优雅地实现 Hystrix 命令的定义,下面通过样例进行演示。
2,同步执行方式
(1)实现同步执行的命令很简单,只要在方法上添加 @HystrixCommand 注解即可:
@Service public class HelloService { @Autowired RestTemplate restTemplate; @HystrixCommand public String hello() { String result = restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class) .getBody(); return result; } }
(2)同步命令的调用执行也很简单:
@RestController public class ConsumerController { @Autowired HelloService helloService; @GetMapping("/hello-consumer") public String helloConsumer() { return helloService.hello(); } }
3,异步执行方式
(1)下面定义一个异步执行方式的命令,其返回的是一个 Future 对象:
@Service public class HelloService { @Autowired RestTemplate restTemplate; @HystrixCommand public Future<String> hello() { return new AsyncResult<String>() { @Override public String invoke() { return restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class) .getBody(); } }; } }
(2)异步命令的调用执行方式如下:
@RestController public class ConsumerController { @Autowired HelloService helloService; @GetMapping("/hello-consumer") public String helloConsumer() throws InterruptedException, ExecutionException { return helloService.hello().get(); } }
4,响应式执行方式
(1)在使用 @HystrixCommand 注解实现响应式命令时,可以通过 observableExecutionMode 参数来控制是使用 observe() 还是 toObservable() 的执行方式:
(2)我们可以通过如下方式进行订阅:
observableExecutionMode 参数有如下两种可选值:
- ObservableExecutionMode.EAGER :表示使用 observe() 执行方式(这个是默认值,即不设置此参数时就是默认使用该方式)
- ObservableExecutionMode.LAZY :表示使用 toObservable() 的执行方式
@Service public class HelloService { @Autowired RestTemplate restTemplate; //使用observe()执行方式 @HystrixCommand public Observable<String> hello1() { return Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { try { if(!subscriber.isUnsubscribed()) { String result = restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class) .getBody(); subscriber.onNext(result); subscriber.onCompleted(); } } catch (Exception e) { subscriber.onError(e); } } }); } //使用toObservable()执行方式 @HystrixCommand(observableExecutionMode = ObservableExecutionMode.LAZY) public Observable<String> hello2() { return Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { try { if(!subscriber.isUnsubscribed()) { String result = restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class) .getBody(); subscriber.onNext(result); subscriber.onCompleted(); } } catch (Exception e) { subscriber.onError(e); } } }); } }
(2)我们可以通过如下方式进行订阅:
@RestController public class ConsumerController { @Autowired HelloService helloService; @GetMapping("/hello-consumer") public String helloConsumer() { helloService.hello1().subscribe((v) ->{ System.out.println("hello1:" + v); }); helloService.hello2().subscribe((v) ->{ System.out.println("hello2:" + v); }); return ""; } }
(3)observe() 和 toObservable() 虽然都返回了 Observable,但是它们略有不同,区别在于命令是否必须订阅后才会执行命令:
- observe() 返回的是一个 Hot Observable,该命令会在 observe() 调用的时候立即执行,当 Observable 每次被订阅的时候会重放它的行为。
- toObservable() 返回的是一个 Cold Observable,toObservable() 执行之后,命令不会被立即执行,只有当所有订阅者都订阅它之后才会执行。
@RestController public class ConsumerController { @Autowired HelloService helloService; @GetMapping("/hello-consumer") public String helloConsumer() { helloService.hello1(); // 即使没有订阅也会执行命令(发起请求) helloService.hello2(); // 不会执行命令 return ""; } }