目录
一、maven依赖
二、控制台
三、基于注解限流
四、热点参数限流
五、利用JMeter验证
一、maven依赖
需要注意,利用的版本需要和你的SpringBoot版本匹配!!
Spring-Cloud直接添加如下依赖即可,baba已经帮你指定好版本了。
当然可以点进去spring-cloud-starter-alibaba-sentinel搜索sentinel-core对应的版本
- <dependency>
- <groupId>com.alibaba.cloud</groupId>
- <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
- </dependency>
复制代码 假如是SpringBoot的话,需要手动导入包。
我这里利用的是SpringBoot Version 2.2.5.RELEASE,对应的版本是1.7.1 (你要根据自己SpringBoot版本查询对应版本,假如版本不对应的话根本用不了)
- <sentinel.version>1.7.1</sentinel.version>
- <!--sentinel核心包-->
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-core</artifactId>
- <version>${sentinel.version}</version>
- </dependency>
- <!--sentinel注解支持模块-->
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-annotation-aspectj</artifactId>
- <version>${sentinel.version}</version>
- </dependency>
- <!--sentinel与控制台交互-->
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-transport-simple-http</artifactId>
- <version>${sentinel.version}</version>
- </dependency>
复制代码 二、控制台
这里也介绍下控制台的利用方法,但我的项目是没运维给我安装这个东西,就没法用它。。
下载地址:Release v1.7.1 · alibaba/Sentinel · GitHub
利用命令启动jar包
java -jar sentinel-dashboard-17.1.jar
前端访问:localhost:8080, 账号密码 默认都是 sentinel
但是但是!!!!!!!界面是空的!!!!!!!!!
启动命令需要指定你的项目标端口,以及名称才行:
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dcsp.sentinel.api.port=8998 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.1.jar
以下是各个命令的介绍:
-Dserver.port=9000 运行端口
-Dcsp.sentinel.dashboard.server=localhost:9000 浏览器访问地址
-Dproject.name=sentinel-dashboard 项目名称
-Dcsp.sentinel.api.port=8092 sentinel客户端端口
-Dsentinel.dashboard.auth.username=username,设置用户名
-Dsentinel.dashboard.auth.password=password,设置访问密码
三、基于注解限流
我的项目没法利用控制台举举措态修改规则,只能在数据库表里面写好规则,系统启动的时候举行读取(当然可以动态修改规则无须重启)
1、maven引入依赖:
- <!--sentinel核心包-->
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-core</artifactId>
- <version>${sentinel.version}</version>
- </dependency>
- <!--sentinel注解支持模块-->
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-annotation-aspectj</artifactId>
- <version>${sentinel.version}</version>
- </dependency>
复制代码 2、创建SentinelConfig类,启用注解
- import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- @Slf4j
- @Configuration
- public class SentinelConfig {
- @Bean
- public SentinelResourceAspect sentinelResourceAspect() {
- return new SentinelResourceAspect();
- }
- }
复制代码 3、创建表 system_sentinel_config 规则设置表
- DROP TABLE IF EXISTS `system_sentinel_config`;
- CREATE TABLE `system_sentinel_config` (
- `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增id',
- `module_name` varchar(100) NOT NULL COMMENT '资源名称',
- `resource` varchar(100) NOT NULL COMMENT '资源名称(唯一), 对应{@link SentinelResName}',
- `desc` varchar(100) NOT NULL COMMENT '资源描述',
- `grade` tinyint(1) NOT NULL DEFAULT 1 COMMENT '阈值类型, 0: 线程数, 1: QPS',
- `count` bigint(20) NOT NULL COMMENT '如果grade为线程数, 表示每秒最高线程数。如果grade为QPS, 表示每秒最高访问量。',
- `strategy` tinyint(1) NOT NULL DEFAULT 0 COMMENT '流控模式。0:直接, 1: 关联, 2:链路',
- `control_behavior` tinyint(1) NOT NULL DEFAULT 0 COMMENT '流控效果。0:默认(直接拒绝), 1: Warm Up(冷启动), 2:匀速排队 3: 冷启动+匀速排队',
- `max_queueing_time_ms` int DEFAULT NULL COMMENT '流控效果为匀速排队时,队列的排队时间(单位:毫秒),需要注意这里类型是int, 并且单位是毫秒',
- `warm_up_period_sec` int DEFAULT NULL COMMENT '冷启动到达最大值的时间(单位:秒)',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
- `create_user` VARCHAR(50) DEFAULT NULL COMMENT '创建人' ,
- `update_user` VARCHAR(50) DEFAULT NULL COMMENT '更新人' ,
- PRIMARY KEY (`id`),
- UNIQUE KEY resource_key(`resource`)
- ) ENGINE=InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET=utf8 COMMENT='sentinel限流配置表';
- -- 标准对接--档案类
- INSERT INTO `system_sentinel_config` (`module_name`, `resource`, `desc`, `grade`, `count`, `strategy`, `control_behavior`, `max_queueing_time_ms`, `warm_up_period_sec`) VALUES
- ('标准对接--档案类', 'standard:structure:add', '新增/编辑建筑类节点(片区/楼栋/单元/住家)', 1, 20, 0, 0, null, null),
- ('标准对接--档案类', 'standard:structure:delete', '删除建筑类节点(片区/楼栋/单元/住家)', 1, 20, 0, 0, null, null),
- ('标准对接--档案类', 'standard:file:upload', '上传图片', 1, 20, 0, 0, null, null),
- ('标准对接--档案类', 'standard:check:face', '人脸质量校验', 1, 20, 0, 0, null, null),
- ('标准对接--档案类', 'standard:household:add', '新增/编辑住户(业主,租户)', 1, 20, 0, 0, null, null),
- ('标准对接--档案类', 'standard:household:delete', '删除住户', 1, 20, 0, 0, null, null),
- ('标准对接--档案类', 'standard:visitor:add', '新增/编辑访客', 1, 20, 0, 0, null, null),
- ('标准对接--档案类', 'standard:visitor:delete', '删除访客', 1, 20, 0, 0, null, null);
- -- 标准对接--其它
- INSERT INTO `system_sentinel_config` (`module_name`, `resource`, `desc`, `grade`, `count`, `strategy`, `control_behavior`, `max_queueing_time_ms`, `warm_up_period_sec`) VALUES
- ('标准对接--其它', 'standard:remote:open', '第三方远程开门', 1, 20, 0, 0, null, null),
- ('标准对接--其它', 'standard:smart:lock:control', '第三方锁门禁权限冻结/解冻', 1, 20, 0, 0, null, null),
- ('标准对接--其它', 'standard:smart:lock:set:temporary:pwd', '第三方锁临时密码下发', 1, 20, 0, 0, null, null);
复制代码 4、对应的SystemSentinelConfigDO对象
- import com.alibaba.csp.sentinel.slots.block.RuleConstant;
- import com.whysu.scd.base.common.constant.sentinel.SentinelResName;
- import lombok.Data;
- import lombok.EqualsAndHashCode;
- /**
- * sentinel限流配置表(SystemSentinelConfig)实体类
- */
- @Data
- public class SystemSentinelConfigDO {
- /**
- * 主键id
- */
- private Long id;
- /**
- * 资源名称
- */
- private String moduleName;
- /**
- * 资源名称(唯一), 对应{@link SentinelResName}
- */
- private String resource;
- /**
- * 资源描述
- */
- private String desc;
- /**
- * 阈值类型
- * 0: 线程数 {@link RuleConstant#FLOW_GRADE_THREAD},
- * 1: QPS {@link RuleConstant#FLOW_GRADE_QPS}
- */
- private Integer grade;
- /**
- * 如果grade为线程数, 表示每秒最高线程数。
- * 如果grade为QPS, 表示每秒最高访问量。
- */
- private Long count;
- /**
- * 流控模式。
- * 0:直接{@link RuleConstant#STRATEGY_DIRECT},
- * 1:关联{@link RuleConstant#STRATEGY_RELATE},
- * 2:链路{@link RuleConstant#STRATEGY_CHAIN},
- */
- private Integer strategy;
- /**
- * 流控效果。
- * 0:默认(直接拒绝){@link RuleConstant#CONTROL_BEHAVIOR_DEFAULT},
- * 1: Warm Up(冷启动){@link RuleConstant#CONTROL_BEHAVIOR_WARM_UP},
- * 2:匀速排队{@link RuleConstant#CONTROL_BEHAVIOR_RATE_LIMITER},
- * 3: 冷启动+匀速排队{@link RuleConstant#CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER},
- */
- private Integer controlBehavior;
- /**
- * 流控效果为匀速排队时,队列的排队时间(单位:毫秒), 需要注意这里类型是int, 并且单位是毫秒
- */
- private Integer maxQueueingTimeMs;
- /**
- * 冷启动到达最大值的时间(单位:秒)
- */
- private Integer warmUpPeriodSec;
- /**
- * 创建时间
- */
- private Date createTime;
- /**
- * 更新时间
- */
- private Date updateTime;
- /**
- * 创建人(手机号码)
- */
- private String createUser;
- /**
- * 更新人(手机号码)
- */
- private String updateUser;
- }
复制代码 5、系统启动的时候,举行加载。这里的告急方法是。
FlowRuleManager.loadRules(rules);
- public void initFlowRule() {
- // 查询配置
- List<SystemSentinelConfigDO> list = systemSentinelConfigService.selectList();
- if (CollectionUtils.isEmpty(list)) {
- log.error("sentinel限流配置为空!!!!");
- return;
- }
- List<FlowRule> rules = new ArrayList<>();
- for (SystemSentinelConfigDO configDO : list) {
- rules.add(SentinelUtil.getFlowRule(configDO));
- }
- // 加载
- FlowRuleManager.loadRules(rules);
- }
复制代码 SentinelUtil工具类:
- public class SentinelUtil {
- public static void update(List<SystemSentinelConfigDO> list) {
- List<FlowRule> rules = new ArrayList<>();
- for (SystemSentinelConfigDO configDO : list) {
- rules.add(SentinelUtil.getFlowRule(configDO));
- }
- // 加载
- FlowRuleManager.loadRules(rules);
- }
- public static List<FlowRule> getFlowRuleList() {
- return FlowRuleManager.getRules();
- }
- public static FlowRule getFlowRule(SystemSentinelConfigDO configDO) {
- // 限流规则
- FlowRule rateRule = new FlowRule();
- // 设置资源名,即流量控制规则的作用对象
- rateRule.setResource(configDO.getResource());
- // 设置限流阈值
- rateRule.setCount(configDO.getCount());
- // 限流阈值类型
- rateRule.setGrade(configDO.getGrade());
- // 流控模式
- rateRule.setStrategy(configDO.getStrategy());
- // 流控效果
- rateRule.setControlBehavior(configDO.getControlBehavior());
- // 流控效果为匀速排队时,队列的排队时间(单位:毫秒), 需要注意这里类型是int, 并且单位是毫秒
- if (configDO.getMaxQueueingTimeMs() != null && configDO.getMaxQueueingTimeMs() != 0) {
- rateRule.setMaxQueueingTimeMs(configDO.getMaxQueueingTimeMs());
- }
- // 冷启动到达最大值的时间(单位:秒)
- if (configDO.getWarmUpPeriodSec() != null && configDO.getWarmUpPeriodSec() != 0) {
- rateRule.setWarmUpPeriodSec(configDO.getWarmUpPeriodSec());
- }
- return rateRule;
- }
- }
复制代码 6、通过update方法动态更新:
- @Transactional
- @Override
- public void update(SystemSentinelConfigDO configDO) {
- ValidateUtils.checkBlank(configDO.getResource());
- SystemSentinelConfigDO dbDO = systemSentinelConfigDao.selectByResource(configDO.getResource());
- if (dbDO != null) {
- configDO.setId(dbDO.getId());
- systemSentinelConfigDao.update(configDO);
- }
- // 全部更新
- SentinelUtil.update(systemSentinelConfigDao.selectList(null));
- }
复制代码 7、定义限流畅用返回, 这里的名称是standardLimit
- @Slf4j
- public class StandardBlockHandler {
- /**
- * 标准对接, 触发限流时返回
- */
- public static ThirdResponseDTO<Object> standardLimit(BlockException ex) {
- return ResponseThirdHelper.failResponse(ResultCodeThirdEnum.THIRD_STANDARD_RATE_LIMIT);
- }
- }
复制代码 8、Controller接口通过@SentinelResource指定资源名称,以及触发限流时的返回消息
- @RestController
- @RequestMapping("/third/archives")
- @Slf4j
- @RequiredArgsConstructor
- public class StandardThirdArchivesController {
- private final StandardArchivesService standardArchivesService;
- /**
- * 新增/编辑建筑类节点(片区/楼栋/单元/住家)
- */
- @PostMapping("/structure/addEdit")
- @SentinelResource(value = "standard:structure:add", blockHandler = "standardLimit", blockHandlerClass = {StandardBlockHandler.class})
- public ThirdResponseDTO<StandardStructureAddRes> addEditStructure(@RequestBody @Validated ThirdRequestDTO<StandardStructureAddReq> req) {
- return ResponseThirdHelper.successResponse(standardArchivesService.addEditStructure(req.getData(), req.getNeighNo()));
- }
- }
复制代码
四、热点参数限流
很遗憾,前面说的第三点【基于注解限流】的方式,没法具体到热点参数,因为我的项目标“入参”是有些复杂的对象,但热点参数只支持【基本类型】的入参。。。
1、第三点说的【基于注解限流】直接取消,重新来过
2、maven引入依赖
- <!--sentinel核心包-->
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-core</artifactId>
- <version>${sentinel.version}</version>
- </dependency>
- <!--sentinel热点参数限流-->
- <dependency>
- <groupId>com.alibaba.csp</groupId>
- <artifactId>sentinel-parameter-flow-control</artifactId>
- <version>${sentinel.version}</version>
- </dependency>
复制代码 3、我这里的入参 ThirdRequestDTO 里面有个字段 clientId,是我需要限流的热点参数:
- @Data
- public class ThirdRequestDTO<T> {
- /**
- * 授权分配的clientId
- */
- private String clientId;
- }
复制代码 4、因为热点参数只支持QPS,于是可以设置的选项就很少了:
以下是设置表:standard_sentinel_config (需要注意sql查询的时候,desc, count要加单引号。你也可以给这2个参数重定名)
这里表示在duration_in_sec(秒)内,访问resource(资源)超过count (次数) 就举行限流,
假如是热点参数的话,则表示:
在duration_in_sec(秒)内,访问resource(资源)超过client_id_count(次数) 就举行限流,
- DROP TABLE IF EXISTS `standard_sentinel_config`;
- CREATE TABLE `standard_sentinel_config` (
- `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '自增id',
- `resource` varchar(100) NOT NULL COMMENT '资源名称{@link SentinelResName}',
- `desc` varchar(100) NOT NULL COMMENT '资源描述',
- `duration_in_sec` int NOT NULL COMMENT '限流的单位时间(秒)',
- `count` int NOT NULL COMMENT '限流参数',
- `client_id_count` int NOT NULL COMMENT '针对clientId限流参数',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
- create_user VARCHAR(50) DEFAULT NULL COMMENT '创建人' ,
- update_user VARCHAR(50) DEFAULT NULL COMMENT '更新人' ,
- PRIMARY KEY (`id`),
- UNIQUE KEY `resource_key`(`resource`)
- ) ENGINE=InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET=utf8 COMMENT='标准对接限流';
- -- 公共字典
- INSERT INTO `standard_sentinel_config` (`resource`, `desc`, `duration_in_sec`, `count`, `client_id_count`) VALUES
- ('standard:archives', '标准对接--档案类', 1, 60, 10),
- ('standard:query:archives', '标准对接--查询档案类', 1, 60, 10),
- ('standard:other', '标准对接--其它', 1, 60, 10);
复制代码 5、StandardSentinelConfigDO对象
- @Data
- public class StandardSentinelConfigDO {
- /**
- * 主键id
- */
- private Long id;
- /**
- * 资源名称{@link SentinelResName}
- */
- private String resource;
- /**
- * 资源描述
- */
- private String desc;
- /**
- * 限流的单位时间(秒)
- */
- private Integer durationInSec;
- /**
- * 限流参数
- */
- private Integer count;
- /**
- * 针对clientId限流参数
- */
- private Integer clientIdCount;
- /**
- * 创建时间
- */
- private Date createTime;
- /**
- * 更新时间
- */
- private Date updateTime;
- /**
- * 创建人(手机号码)
- */
- private String createUser;
- /**
- * 更新人(手机号码)
- */
- private String updateUser;
- }
复制代码 6、系统启动的时候,加载规则:(告急是通过ParamFlowRuleManager.loadRules)
- import com.alibaba.csp.sentinel.slots.block.RuleConstant;
- import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowItem;
- import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
- import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
- import com.whysu.scd.base.common.enums.ResultCodeEnum;
- import com.whysu.scd.base.common.exception.BusinessException;
- import com.whysu.scd.base.common.util.ValidateUtils;
- import com.whysu.scd.module.standard.dao.StandardPlatformInfoDao;
- import com.whysu.scd.module.standard.dao.StandardSentinelConfigDao;
- import com.whysu.scd.module.standard.entity.StandardSentinelConfigDO;
- import com.whysu.scd.module.standard.service.StandardSentinelService;
- import lombok.RequiredArgsConstructor;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.commons.collections4.CollectionUtils;
- import org.springframework.stereotype.Service;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * 标准对接--限流
- */
- @Slf4j
- @Service
- @RequiredArgsConstructor
- public class StandardSentinelServiceImpl implements StandardSentinelService {
- private final StandardPlatformInfoDao standardPlatformInfoDao;
- private final StandardSentinelConfigDao standardSentinelConfigDao;
- @Override
- public void init() {
- // 查询sentinel配置
- List<StandardSentinelConfigDO> configList = standardSentinelConfigDao.selectList(null);
- if (CollectionUtils.isEmpty(configList)) {
- log.error("标准对接sentinel配置为空!");
- return;
- }
- // 查询所有的clientId
- List<String> clientIdList = standardPlatformInfoDao.selectClientIdList2();
- List<ParamFlowRule> ruleList = new ArrayList<>();
- for (StandardSentinelConfigDO configDO : configList) {
- // 资源名
- ParamFlowRule rule = new ParamFlowRule(configDO.getResource());
- // 指定当前 rule 对应的热点参数索引
- rule.setParamIdx(0);
- // 限流的维度,该策略针对 QPS 限流
- rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
- // 限流的单位时间(秒)
- rule.setDurationInSec(configDO.getDurationInSec());
- // 未使用指定热点参数时,该资源限流大小为50
- rule.setCount(configDO.getCount());
- // 热点参数限流
- if (CollectionUtils.isNotEmpty(clientIdList)) {
- List<ParamFlowItem> itemList = new ArrayList<>();
- for (String clientId : clientIdList) {
- // item1 设置了clientId的限流,单位时间(DurationInSec)内只能访问10次
- ParamFlowItem item1 = new ParamFlowItem().setObject(clientId) // 热点参数 value
- .setClassType(String.class.getName()) // 热点参数数据类型
- .setCount(configDO.getClientIdCount()); // 针对该value的限流值
- itemList.add(item1);
- }
- rule.setParamFlowItemList(itemList);
- }
- ruleList.add(rule);
- }
- // 加载
- ParamFlowRuleManager.loadRules(ruleList);
- }
- @Override
- public void update(StandardSentinelConfigDO configDO) {
- ValidateUtils.checkBlank(configDO.getResource());
- // 查询
- StandardSentinelConfigDO dbDO = standardSentinelConfigDao.selectByResource(configDO.getResource());
- if (dbDO == null) {
- throw new BusinessException(ResultCodeEnum.PUTIAN_PARAM_ERROR);
- }
- // 更新
- configDO.setId(dbDO.getId());
- standardSentinelConfigDao.update(configDO);
- // 重新初始化
- init();
- }
- @Override
- public List<ParamFlowRule> getRuleList() {
- return ParamFlowRuleManager.getRules();
- }
- @Override
- public List<ParamFlowRule> getRuleOfResource(String resource) {
- return ParamFlowRuleManager.getRulesOfResource(resource);
- }
- }
复制代码 7、定义了一个注解:StandardSignature
- @Documented
- @Target({ElementType.TYPE, ElementType.METHOD})
- @Retention(RetentionPolicy.RUNTIME)
- public @interface StandardSignature {
- /**
- * 签名算法版本 2.0
- */
- String version() default ThirdConstant.SignatureVersion.TWO;
- /**
- * 接口权限
- */
- StandardOpenTypeEnum[] openType();
- /**
- * data参数是否不能为空(默认为true表示不能为空)
- */
- boolean dataNotNull() default true;
- }
复制代码 8、针对该注解切面:
这里的核心代码是:
- Entry entry = null;
- try {
- // 调用限流
- entry = SphU.entry(resourceName, EntryType.IN, 1, clientId);
- // 业务代码...
- return proceedingJoinPoint.proceed();
- } catch (BlockException e) {
- // 接口限流
- return ResponseThirdHelper.failResponse(ResultCodeThirdEnum.THIRD_STANDARD_RATE_LIMIT);
- } finally {
- if (entry != null) {
- entry.exit(1, clientId);
- }
- }
复制代码 有2个入参:resourceName和clientId
其中clientId是入参ThirdRequestDTO里面的。
resourceName是通过注解指定的StandardSignature里的opernType参数,查询出来的:
- /**
- * key: 标准对接接口,value: sentinel限流资源名称{@link SentinelResName}
- */
- public static final HashMap<StandardOpenTypeEnum, String> SENTINEL_RESOURCE = new HashMap<StandardOpenTypeEnum, String>() {
- {
- // 标准对接-档案类
- put(StandardOpenTypeEnum.ARCHIVES, SentinelResName.STANDARD_ARCHIVES);
- put(StandardOpenTypeEnum.ARCHIVES_GET_CALL_NO_FIRST4, SentinelResName.STANDARD_ARCHIVES);
- put(StandardOpenTypeEnum.ARCHIVES_STRUCT_ADD, SentinelResName.STANDARD_ARCHIVES);
- put(StandardOpenTypeEnum.ARCHIVES_STRUCT_DELETE, SentinelResName.STANDARD_ARCHIVES);
- put(StandardOpenTypeEnum.ARCHIVES_UPLOAD_FACE_FILE, SentinelResName.STANDARD_ARCHIVES);
- put(StandardOpenTypeEnum.ARCHIVES_CHECK_FACE, SentinelResName.STANDARD_ARCHIVES);
- put(StandardOpenTypeEnum.ARCHIVES_HOUSEHOLD_ADD, SentinelResName.STANDARD_ARCHIVES);
- put(StandardOpenTypeEnum.ARCHIVES_HOUSEHOLD_DELETE, SentinelResName.STANDARD_ARCHIVES);
- put(StandardOpenTypeEnum.ARCHIVES_VISITOR_ADD, SentinelResName.STANDARD_ARCHIVES);
- put(StandardOpenTypeEnum.ARCHIVES_VISITOR_DELETE, SentinelResName.STANDARD_ARCHIVES);
- // 标准对接-查询档案类
- put(StandardOpenTypeEnum.QUERY_ARCHIVES, SentinelResName.STANDARD_QUERY_ARCHIVES);
- put(StandardOpenTypeEnum.QUERY_ARCHIVES_NEIGH, SentinelResName.STANDARD_QUERY_ARCHIVES);
- put(StandardOpenTypeEnum.QUERY_ARCHIVES_TREE_WHOLE, SentinelResName.STANDARD_QUERY_ARCHIVES);
- put(StandardOpenTypeEnum.QUERY_ARCHIVES_TREE_PAGE, SentinelResName.STANDARD_QUERY_ARCHIVES);
- put(StandardOpenTypeEnum.QUERY_ARCHIVES_AREA, SentinelResName.STANDARD_QUERY_ARCHIVES);
- put(StandardOpenTypeEnum.QUERY_ARCHIVES_BUILDING, SentinelResName.STANDARD_QUERY_ARCHIVES);
- put(StandardOpenTypeEnum.QUERY_ARCHIVES_UNIT, SentinelResName.STANDARD_QUERY_ARCHIVES);
- put(StandardOpenTypeEnum.QUERY_ARCHIVES_HOUSE, SentinelResName.STANDARD_QUERY_ARCHIVES);
- put(StandardOpenTypeEnum.QUERY_ARCHIVES_DEVICE, SentinelResName.STANDARD_QUERY_ARCHIVES);
- put(StandardOpenTypeEnum.QUERY_ARCHIVES_DEVICE_STATUS, SentinelResName.STANDARD_QUERY_ARCHIVES);
- put(StandardOpenTypeEnum.QUERY_ARCHIVES_PARKING_INFO, SentinelResName.STANDARD_QUERY_ARCHIVES);
- put(StandardOpenTypeEnum.QUERY_ARCHIVES_PARKING_ROAD_INFO, SentinelResName.STANDARD_QUERY_ARCHIVES);
- put(StandardOpenTypeEnum.QUERY_ARCHIVES_PARKING_CAR_INFO, SentinelResName.STANDARD_QUERY_ARCHIVES);
- put(StandardOpenTypeEnum.QUERY_ARCHIVES_PERSON_INFO, SentinelResName.STANDARD_QUERY_ARCHIVES);
- put(StandardOpenTypeEnum.QUERY_ARCHIVES_DEVICE_INFO, SentinelResName.STANDARD_QUERY_ARCHIVES);
- // 标准对接-其它
- put(StandardOpenTypeEnum.OTHER, SentinelResName.STANDARD_OTHER);
- put(StandardOpenTypeEnum.OTHER_REMOTE_OPEN, SentinelResName.STANDARD_OTHER);
- put(StandardOpenTypeEnum.OTHER_BLOCK_CONTROL, SentinelResName.STANDARD_OTHER);
- put(StandardOpenTypeEnum.OTHER_SEND_TEMPORARY_PWD, SentinelResName.STANDARD_OTHER);
- }
- };
复制代码 其中SentinelResName (对应standard_sentinel_config表的resources字段)
- public class SentinelResName {
- /**
- * 标准对接--档案类
- */
- public static final String STANDARD_ARCHIVES = "standard:archives";
- /**
- * 标准对接--查询档案类
- */
- public static final String STANDARD_QUERY_ARCHIVES = "standard:query:archives";
- /**
- * 标准对接--其它
- */
- public static final String STANDARD_OTHER = "standard:other";
- }
复制代码 OpenType是用的枚举:
- import com.whysu.scd.module.standard.dto.StandardTreeNode;
- import lombok.AllArgsConstructor;
- import lombok.Getter;
- import lombok.experimental.Accessors;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * 允许第三方调用的接口类型集合
- */
- @Getter
- @Accessors(fluent = true)
- @AllArgsConstructor
- public enum StandardOpenTypeEnum {
- // 全部接口
- ALL(1, 0, "全部接口"),
- // 二级
- ARCHIVES(2, ALL.type, "档案类"),
- QUERY_ARCHIVES(3, ALL.type, "查询档案类"),
- QUERY_RECORD(4, ALL.type, "查询记录"),
- OTHER(5, ALL.type, "其它接口"),
- // 档案类,取值范围:100到199
- ARCHIVES_GET_CALL_NO_FIRST4(100, ARCHIVES.type, "获取呼叫号码前四位"),
- ARCHIVES_STRUCT_ADD(101, ARCHIVES.type, "新增/编辑片区/楼栋/单元/住家"),
- ARCHIVES_STRUCT_DELETE(102, ARCHIVES.type, "删除片区/楼栋/单元/住家"),
- ARCHIVES_UPLOAD_FACE_FILE(103, ARCHIVES.type, "上传人脸"),
- ARCHIVES_CHECK_FACE(104, ARCHIVES.type, "人脸质量校验"),
- ARCHIVES_HOUSEHOLD_ADD(105, ARCHIVES.type, "新增/编辑住户(会进行人脸质量校验)"),
- ARCHIVES_HOUSEHOLD_DELETE(106, ARCHIVES.type, "删除住户"),
- ARCHIVES_VISITOR_ADD(107, ARCHIVES.type, "新增/编辑访客(会进行人脸质量校验)"),
- ARCHIVES_VISITOR_DELETE(108, ARCHIVES.type, "删除访客"),
- // 查询档案类,取值范围:200到299
- QUERY_ARCHIVES_NEIGH(200, QUERY_ARCHIVES.type, "查询小区档案"),
- QUERY_ARCHIVES_TREE_WHOLE(201, QUERY_ARCHIVES.type, "查询树结构(全部)"),
- QUERY_ARCHIVES_TREE_PAGE(202, QUERY_ARCHIVES.type, "查询树结构(分页)(小区片区楼栋单元住家地点)"),
- QUERY_ARCHIVES_AREA(203, QUERY_ARCHIVES.type, "查询片区档案(分页)"),
- QUERY_ARCHIVES_BUILDING(204, QUERY_ARCHIVES.type, "查询楼栋档案(分页)"),
- QUERY_ARCHIVES_UNIT(205, QUERY_ARCHIVES.type, "查询单元档案(分页)"),
- QUERY_ARCHIVES_HOUSE(206, QUERY_ARCHIVES.type, "查询房屋档案(分页)"),
- QUERY_ARCHIVES_DEVICE(207, QUERY_ARCHIVES.type, "查询设备档案(分页)"),
- QUERY_ARCHIVES_DEVICE_STATUS(208, QUERY_ARCHIVES.type, "查询设备在离线状态(分页)"),
- QUERY_ARCHIVES_PARKING_INFO(209, QUERY_ARCHIVES.type, "查询车场档案"),
- QUERY_ARCHIVES_PARKING_ROAD_INFO(210, QUERY_ARCHIVES.type, "查询车道档案(分页)"),
- QUERY_ARCHIVES_PARKING_CAR_INFO(211, QUERY_ARCHIVES.type, "查询车辆档案(分页)"),
- QUERY_ARCHIVES_PERSON_INFO(212, QUERY_ARCHIVES.type, "查询人员档案(住户/访客/工作人员)(分页)"),
- QUERY_ARCHIVES_DEVICE_INFO(213, QUERY_ARCHIVES.type, "查询设备详情"),
- // 查询记录类,取值范围:300到399
- QUERY_RECORD_ACCESS_PAGE(300, QUERY_RECORD.type, "查询门禁记录(分页,不能跨月查询)"),
- QUERY_RECORD_TALK_PAGE(301, QUERY_RECORD.type, "查询对讲记录(分页,不能跨月查询)"),
- QUERY_RECORD_CAR_PAGE(302, QUERY_RECORD.type, "查询车辆出入记录(分页,不能跨月查询)"),
- // 其它接口,取值范围:400到499
- OTHER_REMOTE_OPEN(400, OTHER.type, "第三方远程开门"),
- OTHER_BLOCK_CONTROL(401, OTHER.type, "锁门禁权限冻结/解冻"),
- OTHER_SEND_TEMPORARY_PWD(402, OTHER.type, "锁临时密码下发"),
- ;
- /**
- * 允许第三方调用的接口类型
- */
- private final int type;
- /**
- * 父节点接口类型
- */
- private final int parentType;
- /**
- * 描述
- */
- private final String desc;
- }
复制代码 完整的切面代码如下:
- import com.alibaba.csp.sentinel.Entry;
- import com.alibaba.csp.sentinel.EntryType;
- import com.alibaba.csp.sentinel.SphU;
- import com.alibaba.csp.sentinel.slots.block.BlockException;
- import com.fasterxml.jackson.databind.JsonNode;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import com.fasterxml.jackson.databind.node.ObjectNode;
- import com.whysu.scd.base.common.constant.i18n.third.standard.MessageThirdStandard;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.commons.collections4.CollectionUtils;
- import org.apache.commons.lang3.StringUtils;
- import org.aspectj.lang.JoinPoint;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.annotation.*;
- import org.aspectj.lang.reflect.MethodSignature;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.stereotype.Component;
- import org.springframework.web.context.request.RequestAttributes;
- import org.springframework.web.context.request.RequestContextHolder;
- import org.springframework.web.context.request.ServletRequestAttributes;
- import javax.annotation.Resource;
- import javax.servlet.http.HttpServletRequest;
- import java.lang.reflect.Method;
- import java.util.HashSet;
- import java.util.List;
- import java.util.Set;
- /**
- * 标准对接-数字签名校验切面
- */
- @Aspect
- @Component
- @Slf4j
- @Configuration
- public class StandardSignatureValidateAspect {
- @Pointcut(value = "@annotation(com.whysu.scd.module.standard.annotation.StandardSignature)")
- public void signaturePointcut() {
- }
- @Around("signaturePointcut()")
- public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
- MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
- StandardSignature annotation = signature.getMethod().getAnnotation(StandardSignature.class);
- Object[] args = proceedingJoinPoint.getArgs();
- for (Object arg : args) {
- if (arg instanceof ThirdRequestDTO) {
- ThirdRequestDTO requestDTO = (ThirdRequestDTO) arg;
- String clientId = requestDTO.getClientId();
- // 根据openType获取资源名称
- Set<String> resourceSet = new HashSet<>();
- for (StandardOpenTypeEnum openTypeEnum : annotation.openType()) {
- String resourceName = StandardMap.SENTINEL_RESOURCE.get(openTypeEnum);
- if (StringUtils.isNotBlank(resourceName)) {
- resourceSet.add(resourceName);
- }
- }
- // 限流判断
- for (String resourceName : resourceSet) {
- Entry entry = null;
- try {
- // 调用限流
- entry = SphU.entry(resourceName, EntryType.IN, 1, clientId);
- // 业务代码...
- return proceedingJoinPoint.proceed();
- } catch (BlockException e) {
- // 接口限流
- return ResponseThirdHelper.failResponse(ResultCodeThirdEnum.THIRD_STANDARD_RATE_LIMIT);
- } finally {
- if (entry != null) {
- entry.exit(1, clientId);
- }
- }
- }
- }
- }
- return null;
- }
- @AfterReturning(returning = "ret", pointcut = "signaturePointcut()")
- public void doAfterReturning(Object ret) {
- // 处理完请求,返回内容
- log.info("标准对接请求scd, 响应参数为:{}", JacksonUtils.toJson(ret));
- }
- }
复制代码 9、在Controller接口指定注解:
- /**
- * 新增/编辑建筑类节点(片区/楼栋/单元/住家)
- */
- @StandardSignature(openType = StandardOpenTypeEnum.ARCHIVES_STRUCT_ADD)
- @PostMapping("/structure/addEdit")
- public ThirdResponseDTO<StandardStructureAddRes> addEditStructure(@RequestBody @Validated ThirdRequestDTO<StandardStructureAddReq> req) {
- return ResponseThirdHelper.successResponse(standardArchivesService.addEditStructure(req.getData(), req.getNeighNo()));
- }
复制代码
五、利用JMeter验证
起首声明这个工具我不大会用哈哈哈
1、先下载http://jmeter.apache.org/download_jmeter.cgi
2、解压,进入bin目录下执行jmeter.bat即可启动成功。
3、默认语言是英文,进入bin目录修改 jmeter.properties,添加如下设置即可改成中文
language=zh_CN
4、右键添加--线程(用户)-线程组
设置1秒并发100次
5、线程组右键:添加--取样器--HTTP请求
指定请求协议,地址,端口,方式,路径。可以直接在【消息体数据】里面复制json对象。
6、HTTP请求右键:添加--设置元件--HTTP信息头管理器
添加请求头:Content-Type application/json;charset=utf-8
7、HTTP请求右键:添加--断言--相应断言
我这里也不知道咋写,但是我知道我项目标相应码3011是对应限流。
我这里就设置成,相应文本,包含3011,就表示成功
8、线程组右键:添加--监听器--察看结果树
9、线程组右键:启动
查看结果树,被限流了哈哈哈哈^_^、、、。。。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |