Spring Cloud-7-自定义Hystrix请求命令

上文中,介绍了Hystrix断路器的简单使用,是通过注解的方式去实现的, 我们也可以通过继承类的方式来实现.

自定义HystrixCommand

除了使用@HystrixCommand注解,也可以自定义类,继承HystrixCommand类. 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class StringCommand extends HystrixCommand<String> {

private RestTemplate restTemplate;

@Override
protected String getFallback() {
return new String("StringCommand.getFallback");
}

public StringCommand(Setter setter, RestTemplate restTemplate) {
super(setter);
this.restTemplate = restTemplate;
}

@Override
protected String run() throws Exception {
return restTemplate.getForObject("http://EUREKA-CLIENT/dc", String.class);
}
}

创建StringCommand类,注入RestTemplate,然后重写getFallback(),run()这两个方法,还有创建一个构造方法.

  • getFallback(): 服务调用失败时回调.
  • run():执行请求时调用
  • 构造方法:第一个参数主要用来保存一些分组信息

同步调用和异步调用

StringCommand搞好后,就可以在controller中调用了,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
@GetMapping("/testStringCommand")
public String testStringCommand() throws ExecutionException, InterruptedException {
StringCommand stringCommand = new StringCommand(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("")), restTemplate);
// 同步调用
// String str = stringCommand.execute();
// log.info("同步调用:{}", str);

// 异步调用
Future<String> queue = stringCommand.queue();
String str1 = queue.get();

return str1;
}

这里可以看到,有两种方式执行请求,第一个是调用stringCommand对象的execute()方法,发起一个同步请求, 第二种是调用queue()方法发起一个异步请求.

同步请求可以直接返回请求结果,而异步请求中,我们需要通过get()方法来获取请求结果.

测试

开启注册中心,启动两个服务提供者应用,还是一个端口8081,一个8082,然后启动当前的消费者工程, 最后关掉8081端口的应用.此时访问http://localhost:9000/testStringCommand,就会间隔的看到以下界面:
image

image

第一个界面中的信息,就是我们在StringCommand类中定义的getFallback()方法返回的.就是服务调用失败的时候调用的

通过注解实现异步请求

之前我们使用注解配置Hystrix,是这样的:

1
2
3
4
@HystrixCommand(fallbackMethod = "helloFallback")
public String helloService(){
return restTemplate.getForObject("http://EUREKA-CLIENT/dc", String.class);
}

这是同步请求的方式,那么如何通过注解实现异步请求呢?

首先,我们需要在配置类(Config.java)中注入HystrixCommandAspect类,具体代码如下:

1
2
3
4
@Bean
public HystrixCommandAspect hystrixCommandAspect(){
return new HystrixCommandAspect();
}

然后通过AsyncResult来执行调用,还是使用@HystrixCommand,方法如下(在HelloService.java):

1
2
3
4
5
6
7
8
9
@HystrixCommand
public Future<String> async(){
return new AsyncResult<String>() {
@Override
public String invoke() {
return restTemplate.getForObject("http://EUREKA-CLIENT/dc", String.class);
}
};
}

然后再controller中调用

1
2
3
4
5
6
7
@GetMapping("/asyncGetResult")
public String asyncGetResult() throws ExecutionException, InterruptedException, TimeoutException {
Future<String> stringFuture = helloService.async();

// get()方法可以设置超时时长
return stringFuture.get(2, TimeUnit.SECONDS);
}

这里项目启动,然后第一次调用会报java.util.concurrent.TimeoutException: null,这个错.暂时没找到原因.