HystrixCommand实战
1. HystrixCommand实战
1.1. 需求
- 由于前端公共调用入口接口代码,封装在单独的jar包,它不属于springCloud管理,所以不适合用注解的方式@HystrixCommand进行服务降级
- 这里直接通过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实战的更多相关文章
- Hystrix请求命令 HystrixCommand、HystrixObservableCommand
Hystrix有两个请求命令 HystrixCommand.HystrixObservableCommand. HystrixCommand用在依赖服务返回单个操作结果的时候.又两种执行方式 -ex ...
- SpringCloud实战-Hystrix请求熔断与服务降级
我们知道大量请求会阻塞在Tomcat服务器上,影响其它整个服务.在复杂的分布式架构的应用程序有很多的依赖,都会不可避免地在某些时候失败.高并发的依赖失败时如果没有隔离措施,当前应用服务就有被拖垮的风险 ...
- SpringCloud(6)---熔断降级理解、Hystrix实战
SpringCloud(6)---熔断降级理解.Hystrix实战 一.概念 1.为什么需要熔断降级 (1)需求背景 它是系统负载过高,突发流量或者网络等各种异常情况介绍,常用的解决方案. 在一个分布 ...
- springcloud微服务实战:Eureka+Zuul+Feign/Ribbon+Hystrix Turbine+SpringConfig+sleuth+zipkin
相信现在已经有很多小伙伴已经或者准备使用springcloud微服务了,接下来为大家搭建一个微服务框架,后期可以自己进行扩展.会提供一个小案例: 服务提供者和服务消费者 ,消费者会调用提供者的服务,新 ...
- SpringCloud实战3-Hystrix请求熔断与服务降级
我们知道大量请求会阻塞在Tomcat服务器上,影响其它整个服务.在复杂的分布式架构的应用程序有很多的依赖,都会不可避免地在某些时候失败.高并发的依赖失败时如果没有隔离措施,当前应用服务就有被拖垮的风险 ...
- 微服务SpringCloud+Docker入门到高级实战(教程详情)
第一章 课程介绍和学习路线 1.微服务架构SpringCloud课程介绍 简介:课程介绍和课程大纲讲解,讲课风格和重点内容理解技巧 2.技术选型和学后水平 简介:课程所需基础和技术选型讲解,学完课程可 ...
- spring-cloud-kubernetes的服务发现和轮询实战(含熔断)
本文是<spring-cloud-kubernetes实战系列>的第四篇,主要内容是在kubernetes上部署两个应用:Web-Service和Account-Service,通过spr ...
- springcloud微服务实战:Eureka+Zuul+Ribbon+Hystrix+SpringConfig
原文地址:http://blog.csdn.net/yp090416/article/details/78017552 springcloud微服务实战:Eureka+Zuul+Ribbon+Hyst ...
- Hystrix原理与实战
Hystrix原理与实战 背景 分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务. 比如:订单服务调用商品服务,商品服务调用库存服务. 对于同步调用,当库存服务不可用时,商品 ...
随机推荐
- MyEclipse 编译错误 web项目中的 js,jsp报错 更改
搜索 validation 语法检测 必须 选定一个 不然不编译
- SSM框架中各层的含义和联系
一.pojo层 也有人称其为model.domain.bean等,pojo层是对应的数据库表的实体类. 二.1.持久层:Dao层(Mapper) Dao(Data access object)层,称为 ...
- 字符模式console usb串口安装centos
黄色部分是使用console口安装centos需要使用text模式,可以参考前文,同时镜像路径也是需要指定的,来自/dev/sda4 U盘 setparams 'Install CentOS 7' l ...
- JavaScript数据类型,构造函数
JavaScript 的数据类型分为两类:原始类型和对象类型. JavaScript中的原始类型包括数字.字符串和布尔值 JavaScript中有两种特殊的原始值:null和undefined. Ja ...
- css设置文本自动换行
.wrap-90 { display: inline-block; word-wrap: break-word;//对块级元素设置此属性 width: 90px;}
- X of a Kind in a Deck of Cards LT914
In a deck of cards, each card has an integer written on it. Return true if and only if you can choos ...
- SpringBoot放置在static下面的静态页面无法访问
最近写项目本来写的好好的,突然static的静态页面访问不了了. 于是我各种上网查资料,看大佬的解决方案,还是没有解决. 直到发现了这篇文章 https://blog.csdn.net/cmqwan/ ...
- ELK的高级篇(测试记录各种日志)
一.elk架构已经完成情况情况下 访问限制: 加个x-pack插件 1)一个脚本收集多个日志,if 判断写入es的索引 [root@k8s6 conf.d]# cat file.conf inpu ...
- 爸爸在家庭中最应该扮演的角色,是爸爸本爸!zz
不然呢?还是爸爸应该cosplay什么物种?细想下,爸爸这个角色很多人是不称职的,经常加班或完全不管孩子的隐形人.肆意把脾气撒在孩子身上的炸弹君.动不动就不耐烦的刺猬......孩子经常挂在嘴边的不是 ...
- spring实现一个简单的事务管理
前两天给公司的数据库操作加了事务管理,今天博客就更一下这个吧. 先说明:本文只是简单得实现一下事务,事务的具体内容,比如事务的等级,事务的具体实现原理等等... 菜鸟水平有限,暂时还更不了这个,以后的 ...