Spring Cloud自定义Hystrix请求命令
在上篇文章中,我们介绍了断路器Hystrix的一个简单使用,主要是通过注解来实现断路器的功能的,不过对于Hystrix的使用,除了注解,我们也可以使用继承类的方式来实现,本文我们就来看看另一种Hystrix的使用方式。
本文是Spring Cloud系列的第十一篇文章,了解前十篇文章内容有助于更好的理解本文:
1.使用Spring Cloud搭建服务注册中心
2.使用Spring Cloud搭建高可用服务注册中心
3.Spring Cloud中服务的发现与消费
4.Eureka中的核心概念
5.什么是客户端负载均衡
6.Spring RestTemplate中几种常见的请求方式
7.RestTemplate的逆袭之路,从发送请求到负载均衡
8.Spring Cloud中负载均衡器概览
9.Spring Cloud中的负载均衡策略
10.Spring Cloud中的断路器Hystrix
本文所使用的服务注册中心、服务提供者和服务消费者都是我们在前文中搭建出来的,这里我就不再赘述,不了解的小伙伴请翻看本系列前面几篇文章(文末提供了源码下载)。
自定义HystrixCommand
我们除了使用@HystrixCommand注解,也可以自定义类继承自HystrixCommand,如下:
public class BookCommand extends HystrixCommand<Book> {
private RestTemplate restTemplate;
@Override
protected Book getFallback() {
return new Book("宋诗选注", 88, "钱钟书", "三联书店");
}
public BookCommand(Setter setter, RestTemplate restTemplate) {
super(setter);
this.restTemplate = restTemplate;
}
@Override
protected Book run() throws Exception {
return restTemplate.getForObject("http://HELLO-SERVICE/getbook1", Book.class);
}
}
在BookCommand中注入RestTemplate,然后重写两个方法:一个是getFallback,这个方法将在服务调用失败时回调;另一个是run方法,执行请求时调用。构造方法的第一个参数主要用来保存一些分组信息。
同步调用和异步调用
当BookCommand创建成功之后,我们就可以在我们的Controller中调用它了,如下:
@RequestMapping("/test1")
public Book test1() throws ExecutionException, InterruptedException {
BookCommand bookCommand = new BookCommand(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("")), restTemplate);
//同步调用
//Book book1 = bookCommand.execute();
//异步调用
Future<Book> queue = bookCommand.queue();
Book book = queue.get();
return book;
}
关于这一段调用,我说如下几点:
1.获取到BookCommand对象之后,我们有两种方式来执行请求,一种是调用execute方法发起一个同步请求,另一种是调用queue方法发起一个异步请求。
2.同步请求中可以直接返回请求结果。
3.异步请求中我们需要通过get方法来获取请求结果,在调用get方法的时候也可以传入超时时长。
执行结果如下:
如果我们先启动一个服务注册中心,再启动两个服务提供者实例,再启动一个服务消费者,然后再关掉一个服务提供者,此时再访问,就会间隔的看到如下页面:
通过注解实现异步请求
在上篇文章(Spring Cloud中的断路器Hystrix)中我们使用了注解来配置Hystrix,当时我们的写法如下:
@HystrixCommand
public Book test2() {
return restTemplate.getForObject("http://HELLO-SERVICE/getbook1", Book.class);
}
那么这种请求是一种同步请求的方式,如果我们想要使用注解来实现异步请求怎么办呢?很简单,两个步骤:
1.配置HystrixCommandAspect的Bean
在项目的入口类中配置一个HystrixCommandAspect的Bean,如下:
@Bean
public HystrixCommandAspect hystrixCommandAspect() {
return new HystrixCommandAspect();
}
2.通过AsyncResult来执行调用
还是使用@HystrixCommand注解,但是方法的实现使用AsyncResult,如下:
@HystrixCommand
public Future<Book> test3() {
return new AsyncResult<Book>() {
@Override
public Book invoke() {
return restTemplate.getForObject("http://HELLO-SERVICE/getbook1", Book.class);
}
};
}
OK,如此之后我们就可以通过注解来实现异步调用了。调用方式如下:
@RequestMapping("/test3")
public Book test3() throws ExecutionException, InterruptedException {
Future<Book> bookFuture = bookService.test3();
//调用get方法时也可以设置超时时长
return bookFuture.get();
}
对响应式函数编程的支持
有的小伙伴可能对响应式函数编程情有独钟,Hystrix对此也提供了相应的支持,在我们获取到BookCommand对象之后,也可以通过如下两种方式来获取到一个Observable来对数据进行二次处理:
BookCommand bookCommand = new BookCommand(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("")), restTemplate);
Observable<Book> observe = bookCommand.observe();
Observable<Book> bookObservable = bookCommand.toObservable();
关于Observable小伙伴们可以自行度娘RxJava的用法,我这里就不再赘述,就说下observe和toObservable的区别:
1.observe命令在调用的时候会立即返回一个Observable。
2.toObservable则不会立即返回一个Observable,订阅者调用数据的时候才会执行。
通过注解支持响应式函数编程
当然,响应式函数编程也可以通过注解来实现,如下:
@HystrixCommand
public Observable<Book> test4() {
return Observable.create(new Observable.OnSubscribe<Book>() {
@Override
public void call(Subscriber<? super Book> subscriber) {
if (!subscriber.isUnsubscribed()) {
Book book = restTemplate.getForObject("http://HELLO-SERVICE/getbook1", Book.class);
subscriber.onNext(book);
subscriber.onCompleted();
}
}
});
}
这个时候我们可以通过在注解中添加参数来描述是通过observe还是toObservable来实现,如下:
@HystrixCommand(observableExecutionMode = ObservableExecutionMode.EAGER)表示使用observe模式来执行
@HystrixCommand(observableExecutionMode = ObservableExecutionMode.LAZY)表示使用toObservable模式来执行
OK,Hystrix自定义请求命令我们就先说这么多,整体上来看,还是注解要方便一些。下篇文章我们来看看服务降级的问题。
案例地址:https://github.com/lenve/SimpleSpringCloud
更多JavaEE资料请关注公众号: