项目准备
项目架构如下:
项目搭建
参考:【SpringCloud】Spring Cloud Alibaba 之 Sentinel哨兵介绍入门(二十九)
1、搭建一个Nacos服务
参考项目搭建,用于做项目的注册中心及配置中心,并启动
2、搭建一个Sentinel控制台
参考项目搭建,并启动
3、搭建2个nacos-payment-provider服务
参考项目搭建,springcloud-provider-sentinel-payment9003 和 springcloud-provider-sentinel-payment9004 项目
项目中PaymentController,如下:
1 @RestController
2 public class PaymentController {
3 @Value("${server.port}")
4 private String serverPort;
5
6 public static HashMap<Long, Payment> hashMap = new HashMap<Long, Payment>();
7
8 static {
9 hashMap.put(1L, new Payment(1L, "aaaaaa"));
10 hashMap.put(2L, new Payment(2L, "bbbbbb"));
11 hashMap.put(3L, new Payment(3L, "cccccc"));
12 }
13
14 @GetMapping(value = "/paymentSQL/{id}")
15 public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
16 Payment payment = hashMap.get(id);
17 CommonResult<Payment> result = new CommonResult<Payment>(200, "from server port : " + serverPort, payment);
18 return result;
19 }
20 }
项目中有2个实体类,CommonResult实体类如下:
1 @Data
2 @AllArgsConstructor
3 @NoArgsConstructor
4 public class CommonResult<T> {
5
6 private int code;
7 private String msg;
8 private T data;
9
10 public CommonResult(int code, String msg) {
11 this.code = code;
12 this.msg = msg;
13 }
14 }
Payment实体类
1 @Data
2 @AllArgsConstructor
3 @NoArgsConstructor
4 public class Payment {
5 private Long id;
6 private String serial;
7 }
然后分别启动2个服务
3、搭建1个springcloud-consumer-sentinel-order7994服务(调用者)
a、pom文件如下:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <project xmlns="http://maven.apache.org/POM/4.0.0"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5 <parent>
6 <artifactId>test-springcloud</artifactId>
7 <groupId>com.test</groupId>
8 <version>1.0-SNAPSHOT</version>
9 </parent>
10 <modelVersion>4.0.0</modelVersion>
11
12 <artifactId>springcloud-consumer-sentinel-order7994</artifactId>
13
14 <dependencies>
15
16 <!-- alibaba nacos sentinel -->
17 <dependency>
18 <groupId>com.alibaba.cloud</groupId>
19 <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
20 <version>2.2.1.RELEASE</version>
21 <exclusions>
22 <exclusion>
23 <groupId>com.fasterxml.jackson.dataformat</groupId>
24 <artifactId>jackson-dataformat-xml</artifactId>
25 </exclusion>
26 </exclusions>
27 </dependency>
28
29 <!-- alibaba nacos -->
30 <dependency>
31 <groupId>com.alibaba.cloud</groupId>
32 <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
33 </dependency>
34
35 <!-- openfeign -->
36 <dependency>
37 <groupId>org.springframework.cloud</groupId>
38 <artifactId>spring-cloud-starter-openfeign</artifactId>
39 </dependency>
40
41 <!-- spring boot -->
42 <dependency>
43 <groupId>org.springframework.boot</groupId>
44 <artifactId>spring-boot-starter-web</artifactId>
45 </dependency>
46 <dependency>
47 <groupId>org.springframework.boot</groupId>
48 <artifactId>spring-boot-starter-actuator</artifactId>
49 </dependency>
50 <dependency>
51 <groupId>org.springframework.boot</groupId>
52 <artifactId>spring-boot-devtools</artifactId>
53 <scope>runtime</scope>
54 <optional>true</optional>
55 </dependency>
56 <dependency>
57 <groupId>org.projectlombok</groupId>
58 <artifactId>lombok</artifactId>
59 <optional>true</optional>
60 </dependency>
61 <dependency>
62 <groupId>org.springframework.boot</groupId>
63 <artifactId>spring-boot-starter-test</artifactId>
64 <scope>test</scope>
65 </dependency>
66
67 </dependencies>
68 </project>
View Code
b、application配置文件如下:
1 # 端口
2 server:
3 port: 7994
4
5 spring:
6 application:
7 name: nacos-order-consumer
8 cloud:
9 nacos:
10 discovery:
11 server-addr: localhost:8848
12 sentinel:
13 transport:
14 # 配置Sentinel DashBoard地址
15 dashboard: localhost:8080
16 # 应用与Sentinel控制台交互的端口,应用本地会起一个该端口占用的HttpServer
17 # 默认8719端口,假如端口被占用,依次+1,直到找到未被占用端口
18 port: 8719
19
20
21 management:
22 endpoints:
23 web:
24 exposure:
25 include: '*'
View Code
c、主启动类OrderMain7994
1 @SpringBootApplication
2 @EnableDiscoveryClient
3 //@EnableFeignClients
4 public class OrderMain7994 {
5 public static void main(String[] args) {
6 SpringApplication.run(OrderMain7994.class, args);
7 }
8 }
d、配置类AppConfig,整合Ribbon服务调用
1 @Configuration
2 public class AppConfig {
3 @Bean
4 @LoadBalanced
5 public RestTemplate restTemplate() {
6 return new RestTemplate();
7 }
8 }
e、controller内容如下:
1 @RestController
2 @Slf4j
3 public class CircleBreakerController {
4 public static final String SERVICE_URL = "http://nacos-payment-provider";
5
6 @Autowired
7 private RestTemplate restTemplate;
8
9 @RequestMapping("/consumer/fallback/{id}")
10 public CommonResult<Payment> fallback(@PathVariable("id") Long id) {
11 CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class);
12 if (id == 4) {
13 throw new IllegalArgumentException("IllegalArgumentException, 非法参数");
14 } else if (result.getData() == null) {
15 throw new NullPointerException("NullPointerException,该ID没有对应的记录,空指针异常");
16 }
17
18 return result;
19 }
20
21 }
4、测试验证项目
1)访问地址:http://localhost:7994/consumer/fallback/3,正常获取到provider服务提供者的内容
2)访问地址:http://localhost:7994/consumer/fallback/4,抛异常,非法参数
3)访问地址:http://localhost:7994/consumer/fallback/5,抛异常,空指针异常
@SentinelResource使用
1、@SentinelResource定义资源名
1.1、修改CircleBreakerController中fallback方法,如下:
1 @RequestMapping("/consumer/fallback/{id}")
2 @SentinelResource(value = "fallback") // 没有配置
3 public CommonResult<Payment> fallback(@PathVariable("id") Long id) {
4 ...
5 }
1.2、重新启动项目
1.3、访问地址http://localhost:7994/consumer/fallback/3,并在sentinel控制台设置限流规则
注意这里设置规则的时候,可以直接使用@SentinelResource的value作为资源名
1.4、快速访问地址http://localhost:7994/consumer/fallback/3,限流成功
2、@SentinelResource 中的fallback
fallback负责业务异常和限流时处理
2.1、修改CircleBreakerController中fallback方法,如下:
1 @RequestMapping("/consumer/fallback/{id}")
2 @SentinelResource(value = "fallback", fallback = "handlerFallback") // fallback负责业务异常和限流返回
3 public CommonResult<Payment> fallback(@PathVariable("id") Long id) {
4 ...
5 }
6
7 public CommonResult<Payment> handlerFallback(Long id, Throwable e) {
8 Payment payment = new Payment(id, "null");
9 return new CommonResult(500, "兜底异常处理handlerFallback,Exception内容:" + e.getMessage(), payment);
10 }
2.2、重新启动项目
2.3、访问地址http://localhost:7994/consumer/fallback/4,出现异常由fallback指定的方法处理
2.4、在sentinel控制台设置限流规则,设置QPS为阀值为1
2.5、快速访问地址http://localhost:7994/consumer/fallback/3,限流成功,限流返回内容为fallback指定的方法
3、@SentinelResource 中的blockHandler
blockHandler只负责sentinel控制台配置违规
3.1、修改CircleBreakerController中fallback方法,如下:
1 @RequestMapping("/consumer/fallback/{id}")
2 @SentinelResource(value = "fallback", blockHandler = "blockHandler") // blockHander只负责sentinel控制台配置违规
3 public CommonResult<Payment> fallback(@PathVariable("id") Long id) {
4 ...
5 }
6
7 public CommonResult<Payment> handlerFallback(Long id, Throwable e) {
8 Payment payment = new Payment(id, "null");
9 return new CommonResult(500, "兜底异常处理handlerFallback,Exception内容:" + e.getMessage(), payment);
10 }
11
12 public CommonResult<Payment> blockHandler(Long id, BlockException blockException) {
13 Payment payment = new Payment(id, "null");
14 return new CommonResult(500, "blockHandler-Sentinel限流,Exception内容:" + blockException.getMessage(), payment);
15 }
3.2、重新启动项目
3.3、访问地址http://localhost:7994/consumer/fallback/4,返回参数非法异常
3.4、在sentinel控制台设置限流规则,设置QPS为阀值为1
3.4、快速访问地址http://localhost:7994/consumer/fallback/3,限流成功,限流返回内容为blockHandler指定的方法
4、@SentinelResource 中的fallback和blockHandler同时存在
fallback负责处理异常,blockHandler负责sentinel控制台配置违规
4.1、修改CircleBreakerController中fallback方法,如下:
1 @RequestMapping("/consumer/fallback/{id}")
2 @SentinelResource(value = "fallback", blockHandler = "blockHandler", fallback = "handlerFallback")
3 public CommonResult<Payment> fallback(@PathVariable("id") Long id) {
4 ...
5 }
4.2、重新启动项目
4.3、访问地址http://localhost:7994/consumer/fallback/4,出现异常由fallback指定的方法处理
4.4、在sentinel控制台设置限流规则,设置QPS为阀值为1
4.4、快速访问地址http://localhost:7994/consumer/fallback/3,限流成功,限流返回内容为blockHandler指定的方法
5、@SentinelResource 中的exceptionsToIgnore
排除fallback指定的方法不处理的异常
5.1、修改CircleBreakerController中fallback方法,如下:
1 @RequestMapping("/consumer/fallback/{id}")
2 @SentinelResource(value = "fallback", blockHandler = "blockHandler", fallback = "handlerFallback",
3 exceptionsToIgnore = {IllegalArgumentException.class})
4 public CommonResult<Payment> fallback(@PathVariable("id") Long id) {
5 ...
6 }
5.2、重新启动项目
5.3、访问地址http://localhost:7994/consumer/fallback/4,出现参数异常直接显示,fallback指定的方法不处理异常