<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-coreartifactId>
<version>1.8.1version>
dependency>
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-annotation-aspectjartifactId>
<version>1.8.1version>
dependency>
dependencies>
使用@SentinelResource注解的方式实现需要引入sentinel-annotation-aspectj依赖,还要配置SentinelResourceAspect的bean:
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author wyp
*/
@Configuration
public class SentinelResourceConfig {
/**
* 开启使用@SentinelResource
*/
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
然后才能去用@SentinelResource注解配置规则:
package com.xc.demo.controller;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
/**
* @author wyp
*/
@RestController
@Slf4j
public class TestController {
private static final String RESOURCE_NAME = "flowControl";
private static final String DEGRADE_RESOURCE_NAME = "degrade";
/**
* spring 的初始化方法配置流控规则
*/
@PostConstruct
private void initFlowRules() {
//流控规则
List<FlowRule> rules = new ArrayList<>();
//流控
FlowRule flowRule = new FlowRule();
//设置流控的资源
flowRule.setResource(RESOURCE_NAME);
//设置流控规则-QPS
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
//设置受保护资源阈值-每秒只能访问一次
flowRule.setCount(1);
rules.add(flowRule);
//加载配置好的规则
FlowRuleManager.loadRules(rules);
}
@RequestMapping("/flowControl")
@SentinelResource(value = RESOURCE_NAME,blockHandler = "flowHandler",fallback = "flowFallback")
public String flowControl() {
if (Math.random()>0.7) {
throw new RuntimeException("抛出运行异常");
}
String str = "flowControl";
log.info("=====" + str + "=====");
return str;
}
public String flowHandler(BlockException be) {
be.printStackTrace();
log.info("=====被流控了=====");
return "被流控了";
}
public String flowFallback(Throwable e) {
e.printStackTrace();
log.info("=====抛出异常=====");
return "抛出异常";
}
/**
* spring 的初始化方法配置降级规则
*/
@PostConstruct
private void initDegradeRule() {
List<DegradeRule> rules = new ArrayList<>();
DegradeRule degradeRule = new DegradeRule();
//设置熔断降级资源名
degradeRule.setResource(DEGRADE_RESOURCE_NAME);
//设置降级规则-异常数
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
//阈值计数,这里是触发熔断异常数- 2+1
degradeRule.setCount(2);
//可以触发熔断的最小请求数(在活动统计时间跨度内)-2
degradeRule.setMinRequestAmount(2);
//统计时间间隔,单位ms -1分钟
degradeRule.setStatIntervalMs(60*1000);
//熔断器打开时的恢复超时(以秒为单位)。超时后,断路器将转换为半开状态以尝试一些请求
degradeRule.setTimeWindow(10);
rules.add(degradeRule);
//加载配置好的规则
DegradeRuleManager.loadRules(rules);
}
@RequestMapping("/degrade")
@SentinelResource(value = DEGRADE_RESOURCE_NAME,blockHandler = "degradeHandler")
public String degrade() {
if (Math.random() > 0.5) {
throw new RuntimeException("运行异常");
}
String str = "degrade";
log.info("=====" + str + "=====");
return str;
}
public String degradeHandler(BlockException be) {
be.printStackTrace();
log.info("=====被熔断降级=====");
return "被熔断降级";
}
}
前往:Sentinel 控制台
spring cloud 项目中引入spring-cloud-starter-alibaba-sentinel
依赖,整合了sentinel核心库和控制台。
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
application配置文件中指定控制台的地址与端口号:
spring.cloud.sentinel.transport.dashboard=127.0.0.1:8858
spring.cloud.sentinel.transport
的更多配置com.alibaba.cloud.sentinel.SentinelProperties.Transport
类如下:
/**
* Sentinel api 端口,默认值为 8719TransportConfig.SERVER_PORT 。
*/
private String port = SentinelConstants.API_PORT;
/**
* Sentinel 仪表板地址,地址为空时不会尝试连接仪表板TransportConfig.CONSOLE_SERVER 。
*/
private String dashboard = "";
/**
* 发送心跳间隔毫秒TransportConfig.HEARTBEAT_INTERVAL_MS 。
*/
private String heartbeatIntervalMs;
/**
* 获取心跳客户端本地ip。如果没有配置客户端 ip,它将是本地主机的地址。该地址需要可以被sentinel客户端所访问到。
*/
private String clientIp;
为了方便,可创建统一异常处理BlockException异常的类实现BlockExceptionHandler接口。
package com.xc.consume.handler;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xc.consume.domain.SysResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 统一异常处理BlockException
* @author wyp
*/
@Configuration
public class MyBlockExceptionHandler implements BlockExceptionHandler {
Logger log = LoggerFactory.getLogger(this.getClass());
public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
log.info("BlockExceptionHandler--全局BlockException处理=====" + e.getRule());
SysResult sysResult = null;
if (e instanceof FlowException) {
sysResult = SysResult.fail(100,"流量控制");
} else if (e instanceof DegradeException) {
sysResult = SysResult.fail(101,"服务降级");
} else if (e instanceof ParamFlowException) {
sysResult = SysResult.fail(102,"热点参数限流");
} else if (e instanceof SystemBlockException) {
sysResult = SysResult.fail(103,"系统保护");
} else if (e instanceof AuthorityException) {
sysResult = SysResult.fail(104,"访问控制");
}
//返回json数据
response.setStatus(500);
response.setCharacterEncoding("utf-8");
response.setContentType("application/json");
new ObjectMapper().writeValue(response.getWriter(),sysResult);
}
}
有上述统一异常处理后,当不使用@SentinelResource注解时,遇到的BlockException都会去统一处理;当使用@SentinelResource注解指定资源名后,就算没有指定blockHandler属性,也不会再去统一处理了,控制台会打印异常信息。