Spring Cloud-8-Hystrix的服务降级与异常处理

之前我们用过了fallbackMethod这个东西,本文将详细说一下这个东西,也就是服务降级

服务降级

前文中,fallbackMethod所描述的函数,就是一个备胎,用来实现服务的降级处理,在@HystrixCommand注解中,可以通过fallbackMethod来指定请求失败后调用的方法,在自定义的Hystrix请求命令时, 可以通过重写getFallback()方法来处理服务降级之后的逻辑

使用@HystrixCommand注解指定fallbackMethod方法时,指定的方法要和注解处在同一个类中

指定的这个fallbackMethod方法在执行的过程中,也可能会发生异常,同理我们也可以给这个方法使用@HystrixCommand注解,指定fallbackMethod,比如这样:

1
2
3
4
5
6
7
8
9
10
11
12
@HystrixCommand(fallbackMethod = "helloFallback")
public String helloService(){
return restTemplate.getForObject("http://EUREKA-CLIENT/dc", String.class);
}
@HystrixCommand(fallbackMethod = "fallback2")
public String helloFallback(){
return "error";
}

public String fallback2(){
return "error2";
}

实际使用中,只给必要的方法添加断路器就好了.

异常处理

在调用服务提供者的时候,也可能会出现异常,默认情况下,方法抛了异常就会自动进行服务降级,交给服务降级中的方法去处理,下面看下两种Hystrix请求方式下如何捕捉异常

自定义的Hystrix请求方式

在自定义的Hystrix请求方式下,可以在getFallback中捕捉抛出的异常,修改我们之前的StringCommand类,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Slf4j
public class StringCommand extends HystrixCommand<String> {

private RestTemplate restTemplate;

@Override
protected String getFallback() {
Throwable executionException = getExecutionException();

log.info("Exception:{}", executionException.getMessage());

return new String("StringCommand.getFallback");
}

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

@Override
protected String run() throws Exception {
// 这里就会抛异常,然后我们通过getFallback()方法 捕捉这里抛出的异常
int i = 1 / 0;
return restTemplate.getForObject("http://EUREKA-CLIENT/dc", String.class);
}
}

这里就是在,run()方法中int i = 1 / 0;会抛一个异常,然后我们在getFallback()方法中通过Throwable executionException = getExecutionException();来捕获异常.

之后还是通过http://localhost:9000/testStringCommand来测试.

页面返回:
image

控制台输出:

1
2019-02-21 16:54:45.735  INFO 8324 --- [     hystrix--1] c.eureka.consumer.hystrix.StringCommand  : Exception:/ by zero

这里就已经进行了服务降级

使用注解的方式

如果是用了注解,只需要在服务降级的方法中添加一个,Throwable类型的参数即可,具体代码如下:

1
2
3
4
5
6
7
8
9
10
@HystrixCommand(fallbackMethod = "helloFallback")
public String helloService(){
int i = 1 / 0;
return restTemplate.getForObject("http://EUREKA-CLIENT/dc", String.class);
}

public String helloFallback(Throwable throwable){
log.info("Exception:{}", throwable.getMessage());
return "error";
}

将异常抛给用户

如果有一个异常,我们并不希望进入到服务降级的方法中,而是想让他直接抛给用户,么可以在@HystrixCommand注解中添加异常忽略,代码如下:

1
2
3
4
5
6
7
8
9
10
@HystrixCommand(fallbackMethod = "helloFallback",ignoreExceptions = ArithmeticException.class)
public String helloService(){
int i = 1 / 0;
return restTemplate.getForObject("http://EUREKA-CLIENT/dc", String.class);
}

public String helloFallback(Throwable throwable){
log.info("Exception:{}", throwable.getMessage());
return "error";
}

然后再次调用,执行结果如下:
image
这里可以看到,并没有服务降级,而是直接把错误抛给了用户.

这里的实现原理很简单,因为有一个名叫HystrixBadRequestException的异常不会进入到服务降级方法中去,当我们定义了ignoreExceptions为ArithmeticException.class之后,当抛出ArithmeticException异常时,Hystrix会将异常信息包装在HystrixBadRequestException里边然后再抛出,此时就不会触发服务降级方法了。