背景:
近期项目准备使用sentinel做服务内的限流,熔断操作。记录一下之前使用sentinel过程一直遇到一个问题:明明设置了资源名称,也设置了blockHandler的对应方法,但是还是会一直报com.alibaba.csp.sentinel.slots.block.flow.FlowException: null。
1.上代码
@Service
public class TestServiceImpl implements TestService {
@Override
@SentinelResource(value = "doSomeThing", blockHandler = "exceptionHandler")
public void doSomeThing(String str) {
System.out.println(str);
return "正常返回";
}
// 限流与阻塞处理
public String exceptionHandler(String str, BlockException ex) {
System.out.println( "blockHandler:" + str+"error:{}"+ex.getMessage());
return "限流中";
}
}
限流规则:
private void loadFlowRules(){
List<FlowRule> flowRules = new ArrayList<>();
FlowRule flowRule = new FlowRule();
flowRule.setResource("doSomeThing");
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
// Set limit QPS to 20.
flowRule.setCount(20);
flowRules.add(flowRule);
FlowRuleManager.loadRules(flowRules);
}
启动后,通过jmeter调用就是报错。
2.解决办法
网上有很多解决办法
检查兜底方法testBlockHandler
的参数是BlockedException还是BlockException,正确参数应该是BlockException,BlockedException是security的,与sentinel无关;检查兜底方法testBlockHandler 是否是public statis静态的,不能定义为private,且必须是statis
检查保证@SentinelResource注解的value与@RequestMapping的value不一致
尝试之后还是不行,最后发现:
- 实现处理函数,该函数的传参必须与资源点的传参一样,并且最后加上
BlockException
异常参数;同时,返回类型也必须一样。
也就是说在上述的方法中, doSomeThing是void返回类型,然而exceptionHandler是String返回。两者不同,所以要两个方法换成一样的返回类型就可以了,代码如下:解决了
@Service
public class TestServiceImpl implements TestService {
@Override
@SentinelResource(value = "doSomeThing", blockHandler = "exceptionHandler")
public String doSomeThing(String str) {
System.out.println(str);
return "正常返回";
}
// 限流与阻塞处理
public String exceptionHandler(String str, BlockException ex) {
System.out.println( "blockHandler:" + str+"error:{}"+ex.getMessage());
return "限流中";
}
}