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原理与实战 背景 分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务. 比如:订单服务调用商品服务,商品服务调用库存服务. 对于同步调用,当库存服务不可用时,商品 ...
随机推荐
- Python之路(第三十三篇) 网络编程:socketserver深度解析
一.socketserver 模块介绍 socketserver是标准库中的一个高级模块,用于网络客户端与服务器的实现.(version = "0.4") 在python2中写作S ...
- CSL的字符串
链接:https://ac.nowcoder.com/acm/contest/551/D 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他语言1048 ...
- ORB-SLAM2的安装和运行流程
一.ORB-SLAM2安装 1.在https://github.com/raulmur/ORB_SLAM2上git clone到当前文件夹内,若想下载到指定文件夹内,就需要cd进入指定文件内,然后再g ...
- Vue history模式支持ie9
vue 路由里面的history能让浏览器显示平常一样的链接,可以去掉#这种,但是在ie9下面会强制变成hash,因为history不支持ie9自动降级,可能就会影响美感,解决:可以在路由里面添加fa ...
- linux系统下部署DNS正向解析
DNS服务概述: DNS(Domain Name System)域名系统,能够提供域名与IP地址的解析服务. 正向解析 正向解析是指域名到IP 地址的解析过程. 部署DNS正向解析 DNS服务的三个配 ...
- HTML表单标签
<form>标签 1.在HTML中,<form></form>标记对用来创建一个表单,即定义表单的开始和结束位置,在标记对之间的一切都属于表单的内容.每个表单元素开 ...
- Django认证系统
一.cooie与session 1.1 cookie与session cooie不属于http协议范围,由于http协议无法保持状态,但实际情况,我们却又要保持状态,因此cookie就是在这样的一个场 ...
- android踩坑日记1
Android四大组件-活动.服务.广播.碎片 情况一 应用场景:定时从服务器获取数据,然后活动或者碎片中根据最新获得的数据,更新UI. 思考: 首先定时,想到定时器,推荐使用系统自带的AlertMa ...
- Geomystery现已上架!
欢迎体验由王涵.程立智.郑昊.蔡镇泽.李明伦.温志成同学开发的几何解谜游戏Geomystery,现已上架Microsoft官方商城! https://www.microsoft.com/zh-cn/s ...
- Runtime "Apache Tomcat v6.0 (3)" is invalid. The JRE could not be found. Edit the server and change the JRE location解决方案
使用eclipse,启动Tomcat时出现The JRE could not be found ,Edit server and change teh JRE location的错误提示! 原因:重装 ...