快速开始
Sentinel 提供了 @SentinelResource
注解用于定义资源,并提供了 AspectJ 的扩展用于自动定义资源、处理 BlockException 等。
1. 引入 Sentinel Annotation AspectJ 依赖
- 在
pom.xml
添加以下Sentinel Annotation AspectJ
注解依赖。
xml
<!-- Sentinel Annotation AspectJ 注解 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.8.2</version>
</dependency>
2. Sentinel 配置切面支持
- 在
cn.calvin.alibaba.sentinel.config
包下,创建SentinelAspectConfig.java
Sentinel 切面配置
java
package cn.calvin.alibaba.sentinel.config;
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Sentinel 配置切面支持
*
* @author Calvin
* @date 2021/9/14
* @since v1.0.0
*/
@Configuration
public class SentinelAspectConfig {
/**
* SentinelResourceAspect 的扩展用于自动定义资源
*
* @return
*/
@Bean
public SentinelResourceAspect sentinelResourceAspect() {
return new SentinelResourceAspect();
}
}
3. 使用 @SentinelResource 注解实现限流和降级
value
: 资源名称,必需项(不能为空)blockHandler
: 对应处理 BlockException 的函数名称,可选项- 函数访问范围需要是 public
- 返回类型需要与原方法相匹配
- 参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException
- 函数默认需要和原方法在同一个类中
- 若希望使用其他类的函数,则可以指定 blockHandlerClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
fallback
: 函数名称,可选项, 用于在抛出异常的时候提供 fallback 处理逻辑。
fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。- 返回值类型必须与原函数返回值类型一致;
- 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异
- 函数默认需要和原方法在同一个类中。
- 若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
exceptionsToIgnore
(since 1.6.0): 用于指定哪些异常被排除掉,不会计入异常统计中,也不会进入 fallback 逻辑中,而是会原样抛出。
java
package cn.calvin.alibaba.sentinel.controller;
import cn.calvin.alibaba.sentinel.domain.User;
import cn.calvin.alibaba.sentinel.exception.ExceptionUtil;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Calvin
* @date 2021/9/14
* @since v1.0.0
*/
@Slf4j
@RestController
@RequestMapping(value = "/api/v1/user")
public class UserController {
@SentinelResource(
value = "/api/v1/user/getById",
fallback = "fallback", fallbackClass = ExceptionUtil.class,
blockHandler = "handleException", blockHandlerClass = ExceptionUtil.class
)
@GetMapping("/getById")
public JSONObject getById(@RequestParam("id") String id) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", 200);
jsonObject.put("msg", "获取用户信息成功!");
jsonObject.put("data", null);
User calvinUser = User
.builder()
.id("1")
.username("Calvin")
.password("******")
.birthday("1994-12-14")
.genden(1)
.build();
if (calvinUser.getId().equals(id)) {
jsonObject.put("data", calvinUser);
} else {
throw new IllegalArgumentException("非法参数异常");
}
return jsonObject;
}
}
- 注解方式埋点不支持
private
方法。 - 1.6.0 之前的版本
fallback
函数只针对降级异常(DegradeException)
进行处理,不能针对业务异常进行处理。 - 若
blockHandler
和fallback
都进行了配置,则被限流降级而抛出BlockException
时只会进入blockHandler
处理逻辑。 - 若未配置
blockHandler、fallback 和 defaultFallback
,则被限流降级时会将BlockException
直接抛出。 - 优先级:
blockHandler > fallback > defaultFallback
。 - 该项目是在第二章 Sentinel 快速开始基础上进行扩展,如启动不了或执行不了,请在这基础上进行添加以上代码和配置。
4. 限流、降级异常处理
- 创建包:
cn.calvin.alibaba.sentinel.exception
- 创建类:
ExceptionUtil.java
- 注意: 这里使用的是上述
@SentinelResource 注解详讲
blockHandler的第五条规则、fallback第四条规则
java
package cn.calvin.alibaba.sentinel.exception;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.fastjson.JSONObject;
/**
* 异常工具类
*
* @author Calvin
* @date 2021/9/14
* @since v1.0.0
*/
public class ExceptionUtil {
/**
* 处理降级异常
*
* @param id 接口参数
* @param e 其他异常抛出
* @return {@link JSONObject}
*/
public static JSONObject fallback(String id, Throwable e) {
JSONObject response = new JSONObject();
JSONObject data = new JSONObject();
data.put("请求参数", id);
data.put("异常信息", e.getMessage());
response.put("msg","异常降级");
response.put("code", 500);
response.put("data", data);
return response;
}
/**
* 处理限流异常
*
* @param id 接口参数
* @param be 限流异常
* @return {@link JSONObject}
*/
public static JSONObject handleException(String id, BlockException be) {
JSONObject response = new JSONObject();
JSONObject data = new JSONObject();
data.put("请求参数", id);
data.put("异常信息", be.getMessage());
response.put("msg","服务限流");
response.put("code", 500);
response.put("data", data);
return response;
}
}