zoukankan      html  css  js  c++  java
  • HystrixCommand实战

    1. HystrixCommand实战

    1.1. 需求

    1. 由于前端公共调用入口接口代码,封装在单独的jar包,它不属于springCloud管理,所以不适合用注解的方式@HystrixCommand进行服务降级
    2. 这里直接通过HystrixCommand的原生实现方式,对服务进行服务降级限流

    1.2. 代码

    package com.zhiyis.common.command;
    
    import com.alibaba.fastjson.JSON;
    import com.netflix.hystrix.*;
    import com.zhiyis.common.bean.bus.OtherFields;
    import com.zhiyis.common.cache.HashMapCache;
    import com.zhiyis.common.model.ErrorMsg;
    import com.zhiyis.common.report.RequestReport;
    import com.zhiyis.common.report.ResponseReport;
    import com.zhiyis.common.service.TableService;
    import com.zhiyis.common.service.TokenService;
    import com.zhiyis.common.utils.ApplicationContextProvider;
    import org.apache.commons.lang.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.util.MultiValueMap;
    import org.springframework.util.ReflectionUtils;
    import org.springframework.web.multipart.MultipartFile;
    import org.springframework.web.multipart.MultipartHttpServletRequest;
    
    import javax.servlet.http.HttpServletRequest;
    import java.lang.reflect.Method;
    import java.util.*;
    
    /**
     * 断路器
     *
     * @author laoliangliang
     * @date 2019/1/2 10:24
     */
    public class RpcCommand extends HystrixCommand<ResponseReport> {
    
        private Logger logger = LoggerFactory.getLogger(this.getClass());
    
        private TableService tableService;
    
        private ApplicationContextProvider applicationContextProvider;
    
        private TokenService tokenService;
    
        private String report;
        private OtherFields fields;
        private HttpServletRequest request;
    
        public RpcCommand(TableService tableService,
                          ApplicationContextProvider applicationContextProvider,
                          TokenService tokenService,
                          String report, OtherFields fields, HttpServletRequest request) {
            super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("rpcGroup"))
                    .andCommandKey(HystrixCommandKey.Factory.asKey("rpcCommand"))
                    .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("rpcThreadPool"))
                    .andCommandPropertiesDefaults(HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(3000)));
            this.tableService = tableService;
            this.applicationContextProvider = applicationContextProvider;
            this.tokenService = tokenService;
            this.report = report;
            this.fields = fields;
            this.request = request;
        }
    
        @Override
        protected ResponseReport run() throws Exception {
            logger.info("The report received :" + report);
            RequestReport requestReport = JSON.parseObject(report, RequestReport.class);
            requestReport.setOtherFields(fields);
            String name = Thread.currentThread().getName();
            long start = System.currentTimeMillis();
            String rand = start + String.valueOf((new Random()).nextInt(10));
            logger.info("—————————————" + rand + "启动线程:" + name + "————————————————————");
            ResponseReport responseReport = new ResponseReport();
            logger.info("The requestReport is:" + report);
            logger.debug("The body is:{}", requestReport.getBody());
            logger.debug("The sign is:{}", requestReport.getHeader().getSign());
            String traCode = requestReport.getHeader().getTra_code();
            if (traCode.isEmpty()) {
                responseReport = responseReport.returnError(ErrorMsg.TRADE_CODE_IS_EMPTY, requestReport);
            } else {
                Map<String, Object> rpcMap = HashMapCache.RPC_INFO.get(traCode);
                if (rpcMap != null) {
                    //判断是否需要校验Token
                    if (rpcMap.get("is_token_check") != null && String.valueOf(rpcMap.get("is_token_check")).equals("1")) {
                        String token = requestReport.getHeader().getToken();
                        if (StringUtils.isEmpty(token)) {
                            responseReport = responseReport.returnError(ErrorMsg.TOKEN_IS_EMPTY, requestReport);
                            return responseReport;
                        } else {
                            switch (tokenService.checkToken(token)) {
                                case 0:
                                    responseReport = responseReport.returnError(ErrorMsg.TOKEN_IS_INVALID, requestReport);
                                    return responseReport;
                                case 2:
                                    responseReport = responseReport.returnError(ErrorMsg.TOKEN_TRA_CODE_NOT_CONIG, requestReport);
                                    return responseReport;
                            }
                        }
                    }
                    String tableName = (String) rpcMap.get("tb_name");
                    switch ((int) rpcMap.get("rpc_type")) {
    //                    增加单条记录
                        case 1:
                            responseReport = tableService.addRecord(rpcMap, tableName, requestReport);
                            break;
    //                    获取单条记录
                        case 2:
                            responseReport = tableService.getRecord(Arrays.asList(((String) rpcMap.get("query_fields")).split(",")), tableName, requestReport);
                            break;
    //                    获取多条记录
                        case 3:
                            responseReport = tableService.getRecords(Arrays.asList(((String) rpcMap.get("query_fields")).split(",")), tableName, requestReport);
                            break;
    //                    修改记录
                        case 4:
                            responseReport = tableService.updateRecord(tableName, ((String) rpcMap.get("query_fields")).split(","), requestReport);
                            break;
    //                    自定义接口
                        case 5:
                            Object clazz = applicationContextProvider.getBean((String) rpcMap.get("class_name"));
                            String methodName = (String) rpcMap.get("class_func_name");
                            Method method = ReflectionUtils.findMethod(clazz.getClass(), methodName, RequestReport.class);
                            responseReport = (ResponseReport) ReflectionUtils.invokeMethod(method, clazz, requestReport);
                            break;
    //                    获取单条记录自定义SQL
                        case 6:
                            responseReport = tableService.getSingleRecordBySQL((String) rpcMap.get("sql_text"), requestReport);
                            break;
    //                    获取多条记录自定义SQL
                        case 7:
                            responseReport = tableService.getMultipleRecordBySQL((String) rpcMap.get("sql_text"), requestReport);
                            break;
    //                    单文件上传的自定义接口
                        case 8:
                            MultipartFile file = null;
                            try {
                                Map<String, MultipartFile> fileMap = ((MultipartHttpServletRequest) request).getFileMap();
                                if (fileMap != null && fileMap.size() != 0) {
                                    file = fileMap.values().iterator().next();
                                }
                            } catch (ClassCastException e) {
                                logger.info("未提供图片");
                            }
                            Object clazz2 = applicationContextProvider.getBean((String) rpcMap.get("class_name"));
                            String methodName2 = (String) rpcMap.get("class_func_name");
                            Method method2 = ReflectionUtils.findMethod(clazz2.getClass(), methodName2, RequestReport.class, MultipartFile.class);
                            responseReport = (ResponseReport) ReflectionUtils.invokeMethod(method2, clazz2, requestReport, file);
                            break;
    //                    单个或多文件上传的自定义接口
                        case 9:
                            List<MultipartFile> fileList = new LinkedList<>();
                            try {
                                MultiValueMap<String, MultipartFile> multiFileMap = ((MultipartHttpServletRequest) request).getMultiFileMap();
                                for (String key : multiFileMap.keySet()) {
                                    for (int i = 0; i < multiFileMap.get(key).size(); i++) {
                                        MultipartFile multipartFile = multiFileMap.get(key).get(i);
                                        fileList.add(multipartFile);
                                    }
                                }
                            } catch (ClassCastException e) {
                                logger.info("未提供图片");
                            }
                            Object clazz3 = applicationContextProvider.getBean((String) rpcMap.get("class_name"));
                            String methodName3 = (String) rpcMap.get("class_func_name");
                            Method method3 = ReflectionUtils.findMethod(clazz3.getClass(), methodName3, RequestReport.class, List.class);
                            responseReport = (ResponseReport) ReflectionUtils.invokeMethod(method3, clazz3, requestReport, fileList);
                            break;
                        default:
                            break;
                    }
                    logger.info("The responseResult is:" + JSON.toJSONString(responseReport));
                }
            }
            long end = System.currentTimeMillis();
            long term = end - start;
            logger.info("—————————————" + rand + "结束线程:" + name + ",耗时:" + term + "ms——————————————");
            return responseReport;
        }
    
        @Override
        protected ResponseReport getFallback() {
            Throwable e = getExecutionException();
            if (e != null) {
                logger.error("rpc 异常",e);
            }
            RequestReport requestReport = JSON.parseObject(report, RequestReport.class);
            ResponseReport responseReport = new ResponseReport();
            return responseReport.returnError("9999", "服务器繁忙,请稍后再试", requestReport);
        }
    
    }
    
    

    这里做个参考,该代码包含了基本配置和异常处理(这里只是打印了下日志)

    1.3. 使用

    
    @ResponseBody
    @RequestMapping(value = "/rpc.api")
    public ResponseReport doRemoteCall(@RequestParam(required = false) String report, OtherFields fields, HttpServletRequest request) {
        RpcCommand rpcCommand = new RpcCommand(tableService, applicationContextProvider, tokenService,
                report,fields,request);
        return rpcCommand.execute();
    }
    
  • 相关阅读:
    Single Round Match 811 1~4 题解
    AtCoder Beginner Contest 215 A~F 题解
    Codeforces Round #739 (Div. 3) 题解
    Codeforces Round #737 (Div. 2) A~E 题解
    Codeforces Round #735 (Div. 2) A~D 题解
    CodeChef Starters 6 Division 3 题解
    AtCoder Beginner Contest 209 题解
    Codeforces Round #732 (Div. 2) A~D题解
    【YBTOJ】约数之和
    【Luogu P7794】[COCI2014-2015#7] JANJE
  • 原文地址:https://www.cnblogs.com/sky-chen/p/10208768.html
Copyright © 2011-2022 走看看