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. 7I - 数塔

    在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的: 有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少? 已经告诉你了,这是个DP的题目 ...

  2. 让终端走socks5代理

    (2017.9.17更新) 方法1: 在终端中直接运行命令 1 export http_proxy=http://proxyAddress:port 这个办法的好处是简单直接,并且影响面很小(只对当前 ...

  3. Reveal Cards In Increasing Order LT950

    In a deck of cards, every card has a unique integer.  You can order the deck in any order you want. ...

  4. HttpWebRequest请求Https协议的WebApi

    public static class RequestClient { /// <summary> /// 参数列表转为string /// </summary> /// &l ...

  5. 在datasnap 中使用unidac 访问数据(客户端)

    前面我们讲了如何使用unidac 在datasnap 的服务端访问数据库,今天大概讲一下客户端如何访问 前面做的服务器?其实这个客户端适合任何datasnap 服务端. 首先我们建一个应用,并加入一个 ...

  6. linux系统下部署DNS反向解析

    DNS服务概述 DNS(Domain Name System)域名系统,能够提供域名与IP地址的解析服务. 反向解析 反向解析是从IP地址到域名的解析过程.主要作用于服务器的身份验证. 部署反向解析 ...

  7. mysql 8 windows 下安装

    1.下载 mysql8 需要下载 window的 zip版本 2.解压 D:\software\mysql\mysql-8.0.16-winx64 2.在这个目录下创建一个 my.ini 的文件 [m ...

  8. PHP中this,self,parent的区别

    {一}PHP中this,self,parent的区别之一this篇 面向对象编程(OOP,Object OrientedProgramming)现已经成为编程人员的一项基本技能.利用OOP的思想进行P ...

  9. C++智能指针 auto_ptr、shared_ptr、weak_ptr和unique_ptr

    手写代码是理解C++的最好办法,以几个例子说明C++四个智能指针的用法,转载请注明出处. 一.auto_ptr auto_ptr这是C++98标准下的智能指针,现在常常已经被C++标准的其他智能指针取 ...

  10. MySQL数据库(五)使用pymysql对数据库进行增删改查

    折腾好半天的数据库连接,由于之前未安装 pip ,而且自己用的python 版本为3.6. 只能用 pymysql 来连接数据库,(如果有和我一样未安装 pip 的朋友请 点这里http://blog ...