基础篇——Spring Cloud Hystrix
一、Hystrix使用之创建请求命令
继承HystrixCommand:
public class UserCommand extends HystrixCommand<User> { private RestTemplate restTemplate; private Long id; public UserCommand(Setter setter, RestTemplate restTemplate, Long id) { super(setter); this.restTemplate = restTemplate; this.id = id; } @Override protected User run() { return restTemplate.getForObject("http://USER-SERVICE/user?id={1}", User.class, id); } }
注:同步执行,User user = new UserCommand(restTemplate, 1L).execute();
异步执行,Future<User> futureUser = new UserCommand(restTemplate, 1L).queue();
Hot Observable,Observable<String> ho = new UserCommand(restTemplate, 1L).observe();
Cold Observable,Observable<String> go = new UserCommand(restTemplate, 1L).toObservable();
注解@HystrixCommand实现同步执行:
public class UserService { @Autowired private RestTemplate restTemplate; @HystrixCommand public User getUserById(Long id) { return restTemplate.getForObject("http://USER-SERVICE/user?id={1}", User.class, id); } }
注解@HystrixCommand实现异步执行:
public class UserService { @Autowired private RestTemplate restTemplate; @HystrixCommand public Future<User> getUserByIdAsync(final String id) { return new AsyncResult<User>() { @Override public User invoke() { return restTemplate.getForObject("http://USER-SERVICE/user?id= {1}", User.class, id); } }; } }
继承HystrixObservableCommand:
public class UserObservableCommand extends HystrixObservableCommand<User> { private RestTemplate restTemplate; private Long id; public UserObservableCommand(Setter setter, RestTemplate restTemplate, Long id) { super(setter); this.restTemplate = restTemplate; this.id = id; } @Override protected Observable<User> construct() { return Observable.create(new Observable.OnSubscribe<User>(){ @Override public void call(Subscribe<? super User> observable) { try { if (!observable.isSubscribed()) { User user = restTemplate.getForObject("http://USER-SERVICE/user?id={1}", User.class, id); observable.onNext(user); observable.onCompleted(); } } catch (Exception e) { observable.onError(e); } } }); } }
注解@HystrixCommand实现响应式命令:
public class UserService { @Autowired private RestTemplate restTemplate; @HystrixCommand public Observable<User> getUserById(final String id) { return Observable.create(new Observable.OnSubscribe<User>() { @Override public void call(Subscribe<? super User> observable) { try { if (!observable.isSubscribe()) { User user = restTemplate.getForObject("http://USER-SERVICE/user?id={1}", User.class, id); observable.onNest(user); observable.onCompleted(); } } catch (Exception e) { observable.onError(e); } } }); } }
二、定义服务降级
对于有返回值的服务,也就是说调用者需要请求服务获取到某些有用的信息,如果在HystrixCommand或HystrixObservableCommand执行出现错误、超时、线程池拒绝、断路器熔断等情况,需要进行服务降级处理来保障调用者的体验。对于继承HystrixCommand执行请求服务,需要重写getFallBack方法;
public class UserCommand extends HystrixCommand<User> { @Override protected User getFallBack() { return new User(); } }
对于继承HystrixObservableCommand执行请求服务,需要重写resumeWithFallBack方法;
public class UserObservableCommand extends HystrixObservableCommand<User> { @Override protected User resumeWithFallBack() { return new User(); } }
对于注解@HystrixCommand执行请求服务,需要使用属性fallBackMethod="方法名",且“方法名”必须在同一类中;
public class UserService { @Autowired private RestTemplate restTemplate; @HystrixCommand(fallBackMethod="defaultUserById") public Observable<User> getUserById(final String id) { return Observable.create(new Observable.OnSubscribe<User>() { @Override public void call(Subscribe<? super User> observable) { try { if (!observable.isSubscribe()) { User user = restTemplate.getForObject("http://USER-SERVICE/user?id={1}", User.class, id); observable.onNest(user); observable.onCompleted(); } } catch (Exception e) { observable.onError(e); } } }); } protected User defaultUserById() { return new User(); } }
当然对于一些不需要服务返回必须有用信息的请求,可以选择不使用服务降级处理,可以直接将错误信息返回给调用者即可。例如:使用HystrixCommand请求写操作的服务,如果写入不成功,直接将错误返回给调用者,通知其稍后重试即可。
三、异常处理
Hystrix执行请求服务的异常有两种,HystrixBadRequestException和其他。因为服务降级策略的存在,除了由HystrixBadRequestException包装的异常外,其他的所有异常都会触发服务降级策略。注解@HystrixCommand通过属性ignoreExceptions实现指定异常向HystrixBadRequestException的包装,当服务请求出现指定异常时,不触发服务降级策略。
当发生服务降级时,获取详细的异常服务,在继承类HystrixCommand或HystrixObserableCommand中,通过其父类方法getExecutionException获得;
@Override protected User getFallBack() { Throwable e = getExecutionException(); return new User(); }
注解@HystrixCommand属性fallBackMethod指定方法中接收参数Throwable e;
protected User defaultUserById(Throwable e) { return new User(); }
四、命令名称、分组以及线程池划分
分组、命令名称和线程池划分是Hystrix对服务请求的细粒化分配,即此次服务请求被分配到某组某个线程池的某个命令,能够更好的统计和分配,在继承方式中设置组名、命令名称和划分的线程池名称;
public UserCommand(RestTemplate restTemplate, Long id) { super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("GroupName")) .andCommandKey(HystrixCommandKey.Factory.asKey("CommandName")) .andThreadPoolKey(HystrixCommandThreadPoolKey.Factory.asKey("ThreadPoolKey"))); this.restTemplate = restTemplate; this.id = id; }
注解@HystrixCommand通过属性groupKey、commandKey、threadPoolKey来设置服务请求的组、命令和线程池划分;
@HystrixCommand(fallBackMethod="defaultUserById", groupKey="UserGroup", commandKey="getUserById", threadPoolKey="userThreadPool") public Observable<User> getUserById(final String id) { return Observable.create(new Observable.OnSubscribe<User>() { @Override public void call(Subscribe<? super User> observable) { try { if (!observable.isSubscribe()) { User user = restTemplate.getForObject("http://USER-SERVICE/user?id={1}", User.class, id); observable.onNest(user); observable.onCompleted(); } } catch (Exception e) { observable.onError(e); } } }); }