1.请求命令
请求命令就是以继承类的方式来代替前面的注解方式。
接着上文,首先定义一个helloCommand:
public class HelloCommand extends HystrixCommand<String> {
RestTemplate restTemplate;
public HelloCommand(Setter setter,RestTemplate restTemplate) {
super(setter);
this.restTemplate = restTemplate;
}
/**
* String类型为上面定义的泛型
* @return
* @throws Exception
*/
@Override
protected String run() throws Exception {
return restTemplate.getForObject("http://provider/hello",String.class);
}
}
调用方法:
@GetMapping("/hello2")
public void hello2(){
HelloCommand helloCommand = new HelloCommand(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("hellojava")), restTemplate);
/** 两种调用方法
* 一、直接调用【同步】
* 【注意:HelloCommand new出来之后只能调用一次,两种方法只执行一次】
* */
String execute = helloCommand.execute();
System.out.println(execute);
HelloCommand helloCommand2 = new HelloCommand(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("hellojava")), restTemplate);
/** 二、先入队,后执行 【异步】*/
String s = null;
try {
Future<String> queue = helloCommand2.queue();
s = queue.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println(s);
}
启动eureka server和provider以及hystrix ,访问http://localhost:3000/hello2 在控制台查看结果。
1.1通过注解实现请求异步调用
@HystrixCommand(fallbackMethod = "error")
public Future<String> hello2(){
return new AsyncResult<String>(){
@Override
public String invoke() {
return restTemplate.getForObject("http://provider/hello",String.class);
}
};
}
@GetMapping("/hello3")
public void hello3(){
Future<String> stringFuture = helloService.hello2();
String s = null;
try {
s = stringFuture.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println(s);
}
重启hystrix项目,访问:http://localhost:3000/hello3 如下:
1.2通过继承方式使用Hystrix, 重写继承类的 getFallback 方法实现服务容错/降级。
public class HelloCommand extends HystrixCommand<String> {
RestTemplate restTemplate;
public HelloCommand(Setter setter,RestTemplate restTemplate) {
super(setter);
this.restTemplate = restTemplate;
}
@Override
protected String run() throws Exception {
return restTemplate.getForObject("http://provider/hello",String.class);
}
/**
* 请求失败的回调
* @return
*/
@Override
protected String getFallback(){
return "error-extends";
}
}
重启hystrix项目 访问hello2接口。(启动2个provider,都注册到eureka,,再关闭一个,刷新才能看到效果,与一开始的注解式方式相似)
2.异常处理
就是当发起服务时,如果不是provider的原因导致请求调用失败,而是 consumer 中本身代码有问题导致的请求失败,即 consumer中抛出了异常,这个时候,也会自动进行服务降级,只不过这个时候降级,我们还需要知道到底哪里出错了。
如下例实例代码,如果hello方法执行时抛出异常,那么一样会进行服务降级,进入到 error 方法中,然后获取到异常的详细及信息。
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
/**
* 在这个方法中,将发起一个远程调用,去调用provider中提供的 /hello接口
* 但是调用这个方法可能会失败,
*
* 所以在方法上面添加 @HystrixCommand ,配置fallbackMethod 属性,这个属性表示该方法调用失败时的临时替代方法
* 【专业术语:服务降级】 */
@HystrixCommand(fallbackMethod = "error")//如果希望直接抛出异常,不做服务降级 。则再加上ignoreExceptions配置(fallbackMethod = "error",ignoreExceptions = ArithmeticException.class)
public String hello(){
int i = 1 / 0;
return restTemplate.getForObject("http://provider/hello",String.class);
}
/**
* 这个方法名要和 fallbackMethod一致
* 方法返回值也要一致 【比如这里都是String类型,error也要一致】
* 此处 调用 备案方案 ,比如数据库崩了,就要去查缓存
*
* * **下面也可以继续写HystrixCommand调用error2 ,然后error2再去调用其它的方法,方法一样,依次往下,这就是【服务降级】
* * **越往下,数据的获取能力越来越容易,准确性可能降低,但不会让系统挂掉。
* * ** 这就是Hystrix 的作用: 1. 降级 2. 容错。 避免雪崩 。
*
* @return
*/
//@HystrixCommand(fallbackMethod = "error2")
public String error(Throwable t){
return "error"+t.getMessage();
}
}
这是注解的方式,也可以通过继承的方式:
public class HelloCommand extends HystrixCommand<String> {
RestTemplate restTemplate;
public HelloCommand(Setter setter,RestTemplate restTemplate) {
super(setter);
this.restTemplate = restTemplate;
}
/**
* String类型为上面定义的泛型
* @return
* @throws Exception
*/
@Override
protected String run() throws Exception {
int i = 1 / 0;//测试异常
return restTemplate.getForObject("http://provider/hello",String.class);
}
/**
* 请求失败的回调
* @return
*/
@Override
protected String getFallback(){
return "error-extends"+getFailedExecutionException().getMessage();
}
}
如果是通过继承的方式来做 Hystrix ,在getFallback 方法中,我们可以通过 getExecutionException 方法来获取执行的异常信息。
另一种可能性。如果抛出异常了,我们希望异常直接抛出,不要服务降级,那么只需要配置忽略某一个异常即可:
@Override
protected String hello() {
int i = 1 / 0;//测试异常
return restTemplate.getForObject("http://provider/hello",String.class);
}
代码示例地址:https://github.com/astronger/springcloud-simple-samples