美文网首页
Hystrix请求命令

Hystrix请求命令

作者: 一腔诗意换酒钱 | 来源:发表于2020-03-04 15:19 被阅读0次

    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中只打印了一条记录

    image

    Hystrix中返回了五个结果

    image

    在获取三条记录后让线程休眠200毫秒,之后继续获取,可以看到provider总共收到两次请求。说明设置的等待时间.andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter().withTimerDelayInMilliseconds(200))可以生效

    image

    相关文章

      网友评论

          本文标题:Hystrix请求命令

          本文链接:https://www.haomeiwen.com/subject/mlnvlhtx.html