Hystrix请求命令
请求命令就是用类的继承的方式来代替注解。
定义HelloCommand类:
public class HelloCommand extends HystrixCommand<String> {
@Autowired
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);
}
}
在controller调用HelloCommand
@GetMapping("/hello2")
public void hello2(){
//拿到helloCommand实例
HelloCommand helloCommand = new HelloCommand(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("zby")), restTemplate);
String execute = helloCommand.execute();//直接执行
System.out.println(execute);
HelloCommand helloCommand2 = new HelloCommand(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("zby")), restTemplate);
try {
Future<String> queue = helloCommand2.queue();//先入队后执行
String s = queue.get();
System.out.println(s);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
注意:一个实例只能执行一次,有两种执行方法
1.直接执行(同步调用)
2.先入队后执行(异步调用)
在command类中重写HystrixCommand的getFallBack()方法,即可实现服务降级的功能
异常处理
执行HsytrixCommand实现的run()方法抛出异常时,除HystrixBadRequestException之外,其他异常都会被认为是Hystrix命令执行失败并触发服务降级处理逻辑。若想要知道异常的具体信息,可以在getFallBack方法中对异常进行处理。
在HystrixCommand类中为我们提供了捕获异常的方法getExecutionException()
可以通过这个方法获取异常的全部信息
@Override
protected String getFallback() {
return "command-error"+getExecutionException().getMessage();
}
请求合并
首先在provider中提供请求合并的接口
@GetMapping("/user/{ids}")//假设从consumer传来多个id,格式为1,2,3...
public List<User> getUserByIds(@PathVariable String ids){
String[] split = ids.split(",");
List<User> users = new ArrayList<>();
for (String s : split) {
User user = new User();
user.setId(Integer.parseInt(s));
users.add(user);
}
return users;
}
将传来的参数合并为一个List数组,根据数组中的每个参数,拿到相应的请求结果的集合。这个接口既可以处理单个请求,也可以处理多个请求。
在Hystrix中定义UserService
@Service
public class UserService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand
public List<User> getUserByIds(List<Integer> ids){
User[] users = restTemplate.getForObject("http://provider/user/{1}", User[].class, StringUtils.join(ids, ","));
return Arrays.asList(users);
}
}
定义一个请求命令类UserBatchCommand用于对服务返回结果进行批处理
public class UserBatchCommand extends HystrixCommand<List<User>> {
private List<Integer> ids;
private UserService userService;
public UserBatchCommand(List<Integer> ids,UserService userService) {
super(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("batchCmd"))
.andCommandKey(HystrixCommandKey.Factory.asKey("batchKey")));
this.ids = ids;
this.userService = userService;
}
@Override
protected List<User> run() throws Exception {
return userService.getUserByIds(ids);
}
}
最后定义请求合并方法,方法继承自HystrixCommand包含有三个泛型:
1.批处理的返回类型List<User>
2.数据响应的的类型,也就是User对象
3.传递的参数类型Integer
public class UserCollapseCommand extends HystrixCollapser<List<User>,User,Integer> {
private UserService userService;
private Integer id;
public UserCollapseCommand(UserService userService, Integer id) {
//请求合并等待时间
super(HystrixCollapser.Setter.withCollapserKey(HystrixCollapserKey.Factory.asKey("UserCollapseCommand"))
.andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter().withTimerDelayInMilliseconds(200)));
this.userService = userService;
this.id = id;
}
/**
* 获取请求参数
* @return
*/
@Override
public Integer getRequestArgument() {
return id;
}
/**
* 请求合并的方法,把合并好的请求放在collection里统一发送
* @param collection
* @return
*/
@Override
protected HystrixCommand<List<User>> createCommand(Collection<CollapsedRequest<User, Integer>> collection) {
List<Integer> ids = new ArrayList<>(collection.size());
for (CollapsedRequest<User, Integer> userIntegerCollapsedRequest : collection) {
ids.add(userIntegerCollapsedRequest.getArgument());
}
return new UserBatchCommand(ids,userService);
}
/**
* 请求结果分发
* 第一个参数是provider返回的结果,第二个参数是合并后请求
* @param users
* @param collection
*/
@Override
protected void mapResponseToRequests(List<User> users, Collection<CollapsedRequest<User, Integer>> collection) {
int count = 0;
for (CollapsedRequest<User, Integer> request : collection) {
request.setResponse(users.get(count++));
}
}
}
配置完成后进行测试:
@GetMapping("/hello5")
public void hello5() throws ExecutionException, InterruptedException {
HystrixRequestContext ctx = HystrixRequestContext.initializeContext();
UserCollapseCommand cmd1 = new UserCollapseCommand(userService,1);
UserCollapseCommand cmd2 = new UserCollapseCommand(userService,2);
UserCollapseCommand cmd3 = new UserCollapseCommand(userService,3);
UserCollapseCommand cmd4 = new UserCollapseCommand(userService,4);
UserCollapseCommand cmd5 = new UserCollapseCommand(userService,5);
Future<User> q1 = cmd1.queue();
Future<User> q2= cmd2.queue();
Future<User> q3 = cmd3.queue();
Future<User> q4 = cmd4.queue();
Future<User> q5 = cmd5.queue();
User u1 = q1.get();
User u2 = q2.get();
User u3 = q3.get();
User u4 = q4.get();
User u5 = q5.get();
System.out.println(u1);
System.out.println(u2);
System.out.println(u3);
System.out.println(u4);
System.out.println(u5);
ctx.close();
}
访问接口,可以看到,在provider中只打印了一条记录
Hystrix中返回了五个结果
在获取三条记录后让线程休眠200毫秒,之后继续获取,可以看到provider总共收到两次请求。说明设置的等待时间.andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter().withTimerDelayInMilliseconds(200))
可以生效