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();
}

HystrixCommand实战的更多相关文章

  1. Hystrix请求命令 HystrixCommand、HystrixObservableCommand

    Hystrix有两个请求命令 HystrixCommand.HystrixObservableCommand. HystrixCommand用在依赖服务返回单个操作结果的时候.又两种执行方式  -ex ...

  2. SpringCloud实战-Hystrix请求熔断与服务降级

    我们知道大量请求会阻塞在Tomcat服务器上,影响其它整个服务.在复杂的分布式架构的应用程序有很多的依赖,都会不可避免地在某些时候失败.高并发的依赖失败时如果没有隔离措施,当前应用服务就有被拖垮的风险 ...

  3. SpringCloud(6)---熔断降级理解、Hystrix实战

    SpringCloud(6)---熔断降级理解.Hystrix实战 一.概念 1.为什么需要熔断降级 (1)需求背景 它是系统负载过高,突发流量或者网络等各种异常情况介绍,常用的解决方案. 在一个分布 ...

  4. springcloud微服务实战:Eureka+Zuul+Feign/Ribbon+Hystrix Turbine+SpringConfig+sleuth+zipkin

    相信现在已经有很多小伙伴已经或者准备使用springcloud微服务了,接下来为大家搭建一个微服务框架,后期可以自己进行扩展.会提供一个小案例: 服务提供者和服务消费者 ,消费者会调用提供者的服务,新 ...

  5. SpringCloud实战3-Hystrix请求熔断与服务降级

    我们知道大量请求会阻塞在Tomcat服务器上,影响其它整个服务.在复杂的分布式架构的应用程序有很多的依赖,都会不可避免地在某些时候失败.高并发的依赖失败时如果没有隔离措施,当前应用服务就有被拖垮的风险 ...

  6. 微服务SpringCloud+Docker入门到高级实战(教程详情)

    第一章 课程介绍和学习路线 1.微服务架构SpringCloud课程介绍 简介:课程介绍和课程大纲讲解,讲课风格和重点内容理解技巧 2.技术选型和学后水平 简介:课程所需基础和技术选型讲解,学完课程可 ...

  7. spring-cloud-kubernetes的服务发现和轮询实战(含熔断)

    本文是<spring-cloud-kubernetes实战系列>的第四篇,主要内容是在kubernetes上部署两个应用:Web-Service和Account-Service,通过spr ...

  8. springcloud微服务实战:Eureka+Zuul+Ribbon+Hystrix+SpringConfig

    原文地址:http://blog.csdn.net/yp090416/article/details/78017552 springcloud微服务实战:Eureka+Zuul+Ribbon+Hyst ...

  9. Hystrix原理与实战

    Hystrix原理与实战 背景 分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务. 比如:订单服务调用商品服务,商品服务调用库存服务. 对于同步调用,当库存服务不可用时,商品 ...

随机推荐

  1. 第一次面试经历(hr面)

    经过介绍,我有幸去到一家国际背景的广告公司面试前端开发实习生.收到的邮件是复试通知,看来我已经跳过了第一轮面试. 来到hr请我进了一个小间坐下里填求职书,里面有各种个人信息,有兴趣爱好,有工作经历,以 ...

  2. mac sublime3 无法安装Package Control

    一.在线安装 1.打开sublime,Ctrl+` 打开控制台, 输入 import urllib.request,os,hashlib; h = '6f4c264a24d933ce70df5dedc ...

  3. 四、PyQt5布局管理(绝对&相对、水平、垂直、格栅、表单)

    目录 一.绝对布局 二.盒布局 三.格栅布局 四.格栅布局跨行跨列显示 布局管理即设置窗体上各个控件的位置,对于新手来说,这是学习的难点. 布局管理根据绝对坐标是否变动分为绝对布局和相对布局两大类.采 ...

  4. WIN10家庭版的升级到企业版

    1.右键点击[此电脑]---->属性 2.点击[激活windows] 3.在左侧点击[激活]--->更改产品密匙 4.然后输入产品密匙:NPPR9-FWDCX-D2C8J-H872K-2Y ...

  5. PM学习梳理--原型设计

  6. ubuntu16.04安装tensorflow1.3

    总结 : 1.点软件个更新-系统更新2.降级gcc到5.33.装CUDA及第二个包,加入PATH4.CUDNN5.Ancada..6.TF Ubuntu16.04 的GCC版本降级 http://bl ...

  7. No rule to make target '/usr/lib/x86_64-linux-gnu/libproj.so ,needed by '../bin/generate_pointcloud解决方法

    这是/usr/lib/x86_64-linux-gnu/文件夹内没有这个libproj.so 库,先在该文件夹内搜索是否有同名不同版本的库,如果有 ,可以使用ln -s在该文件夹内部对存在的库链接到一 ...

  8. dubbo入门学习 四 注册中心 zookeeper入门

    一.Dubbo支持的注册中心 1. Zookeeper 1.1 优点:支持网络集群 1.2 缺点:稳定性受限于Zookeeper 2. Redis 2.1 优点:性能高. 2.2 缺点:对服务器环境要 ...

  9. 对TIMIT数据进行格式转换(SPHERE2WAV(RIFF))

    首先,转换sph2pipe工具所在文件夹(此工具为LDC所提供的SPHERE音频文件转换工具) cd '/home/dream/Research/kaldi-master/tools/sph2pipe ...

  10. 解决redis连接错误:MISCONF Redis is configured to save RDB snapshots, but it is currently not able to...

    今天Redis服务器在连接redis数据库时突然报错:MISCONF Redis is configured to save RDB snapshots, but it is currently no ...