diff --git a/labx-04/labx-04-sca-sentinel-demo01-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/controller/DemoController.java b/labx-04/labx-04-sca-sentinel-demo01-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/controller/DemoController.java
index e85eceb4..5a008fab 100644
--- a/labx-04/labx-04-sca-sentinel-demo01-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/controller/DemoController.java
+++ b/labx-04/labx-04-sca-sentinel-demo01-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/controller/DemoController.java
@@ -1,8 +1,12 @@
package cn.iocoder.springcloudalibaba.labx04.sentineldemo.provider.controller;
+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 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;
@RestController
@@ -34,4 +38,47 @@ public class DemoController {
return "商品编号:" + id;
}
+ // 测试「Sentinel 客户端 API」
+ @GetMapping("/entry_demo")
+ public String entryDemo() {
+ Entry entry = null;
+ try {
+ // <1> 访问资源
+ entry = SphU.entry("entry_demo");
+
+ // <2> ... 执行业务逻辑
+
+ return "执行成功";
+ } catch (BlockException ex) { // <3>
+ return "被拒绝";
+ } finally {
+ // <4> 释放资源
+ if (entry != null) {
+ entry.exit();
+ }
+ }
+ }
+
+ // 测试「Sentinel @SentinelResource 注解」
+ @GetMapping("/annotations_demo")
+ @SentinelResource(value = "annotations_demo_resource",
+ blockHandler = "blockHandler",
+ fallback = "fallback")
+ public String annotationsDemo(@RequestParam(required = false) Integer id) throws InterruptedException {
+ if (id == null) {
+ throw new IllegalArgumentException("id 参数不允许为空");
+ }
+ return "success...";
+ }
+
+ // BlockHandler 处理函数,参数最后多一个 BlockException,其余与原函数一致.
+ public String blockHandler(Integer id, BlockException ex) {
+ return "block:" + ex.getClass().getSimpleName();
+ }
+
+ // Fallback 处理函数,函数签名与原函数一致或加一个 Throwable 类型的参数.
+ public String fallback(Integer id, Throwable throwable) {
+ return "fallback:" + throwable.getMessage();
+ }
+
}
diff --git a/labx-04/labx-04-sca-sentinel-nacos-provider/pom.xml b/labx-04/labx-04-sca-sentinel-nacos-provider/pom.xml
new file mode 100644
index 00000000..fb6cdb06
--- /dev/null
+++ b/labx-04/labx-04-sca-sentinel-nacos-provider/pom.xml
@@ -0,0 +1,72 @@
+
+
+
+ labx-04
+ cn.iocoder.springboot.labs
+ 1.0-SNAPSHOT
+
+ 4.0.0
+
+ labx-04-sca-sentinel-nacos-provider
+
+
+ 1.8
+ 1.8
+ 2.2.4.RELEASE
+ Hoxton.SR1
+ 2.2.0.RELEASE
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ ${spring.boot.version}
+ pom
+ import
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring.cloud.version}
+ pom
+ import
+
+
+ com.alibaba.cloud
+ spring-cloud-alibaba-dependencies
+ ${spring.cloud.alibaba.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-sentinel
+
+
+
+
+ com.alibaba.csp
+ sentinel-datasource-nacos
+
+
+
+
diff --git a/labx-04/labx-04-sca-sentinel-nacos-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/DemoProviderApplication.java b/labx-04/labx-04-sca-sentinel-nacos-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/DemoProviderApplication.java
new file mode 100644
index 00000000..569f4d28
--- /dev/null
+++ b/labx-04/labx-04-sca-sentinel-nacos-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/DemoProviderApplication.java
@@ -0,0 +1,13 @@
+package cn.iocoder.springcloudalibaba.labx04.sentineldemo.provider;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class DemoProviderApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(DemoProviderApplication.class, args);
+ }
+
+}
diff --git a/labx-04/labx-04-sca-sentinel-nacos-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/controller/DemoController.java b/labx-04/labx-04-sca-sentinel-nacos-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/controller/DemoController.java
new file mode 100644
index 00000000..5a008fab
--- /dev/null
+++ b/labx-04/labx-04-sca-sentinel-nacos-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/controller/DemoController.java
@@ -0,0 +1,84 @@
+package cn.iocoder.springcloudalibaba.labx04.sentineldemo.provider.controller;
+
+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 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;
+
+@RestController
+@RequestMapping("/demo")
+public class DemoController {
+
+ // 测试【流量控制】
+ @GetMapping("/echo")
+ public String echo() {
+ return "echo";
+ }
+
+ @GetMapping("/test")
+ public String test() {
+ return "test";
+ }
+
+ // 测试【熔断降级】
+ @GetMapping("/sleep")
+ public String sleep() throws InterruptedException {
+ Thread.sleep(100L);
+ return "sleep";
+ }
+
+ // 测试【热点参数限流】
+ @GetMapping("/product_info")
+ @SentinelResource("demo_product_info_hot")
+ public String productInfo(Integer id) {
+ return "商品编号:" + id;
+ }
+
+ // 测试「Sentinel 客户端 API」
+ @GetMapping("/entry_demo")
+ public String entryDemo() {
+ Entry entry = null;
+ try {
+ // <1> 访问资源
+ entry = SphU.entry("entry_demo");
+
+ // <2> ... 执行业务逻辑
+
+ return "执行成功";
+ } catch (BlockException ex) { // <3>
+ return "被拒绝";
+ } finally {
+ // <4> 释放资源
+ if (entry != null) {
+ entry.exit();
+ }
+ }
+ }
+
+ // 测试「Sentinel @SentinelResource 注解」
+ @GetMapping("/annotations_demo")
+ @SentinelResource(value = "annotations_demo_resource",
+ blockHandler = "blockHandler",
+ fallback = "fallback")
+ public String annotationsDemo(@RequestParam(required = false) Integer id) throws InterruptedException {
+ if (id == null) {
+ throw new IllegalArgumentException("id 参数不允许为空");
+ }
+ return "success...";
+ }
+
+ // BlockHandler 处理函数,参数最后多一个 BlockException,其余与原函数一致.
+ public String blockHandler(Integer id, BlockException ex) {
+ return "block:" + ex.getClass().getSimpleName();
+ }
+
+ // Fallback 处理函数,函数签名与原函数一致或加一个 Throwable 类型的参数.
+ public String fallback(Integer id, Throwable throwable) {
+ return "fallback:" + throwable.getMessage();
+ }
+
+}
diff --git a/labx-04/labx-04-sca-sentinel-nacos-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/web/CustomBlockExceptionHandler.java b/labx-04/labx-04-sca-sentinel-nacos-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/web/CustomBlockExceptionHandler.java
new file mode 100644
index 00000000..6431c62c
--- /dev/null
+++ b/labx-04/labx-04-sca-sentinel-nacos-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/web/CustomBlockExceptionHandler.java
@@ -0,0 +1,18 @@
+package cn.iocoder.springcloudalibaba.labx04.sentineldemo.provider.web;
+
+import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@Component
+public class CustomBlockExceptionHandler implements BlockExceptionHandler {
+
+ @Override
+ public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
+ throw e;
+ }
+
+}
diff --git a/labx-04/labx-04-sca-sentinel-nacos-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/web/CustomRequestOriginParser.java b/labx-04/labx-04-sca-sentinel-nacos-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/web/CustomRequestOriginParser.java
new file mode 100644
index 00000000..546fda81
--- /dev/null
+++ b/labx-04/labx-04-sca-sentinel-nacos-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/web/CustomRequestOriginParser.java
@@ -0,0 +1,23 @@
+package cn.iocoder.springcloudalibaba.labx04.sentineldemo.provider.web;
+
+import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
+import org.springframework.stereotype.Component;
+import org.springframework.util.StringUtils;
+
+import javax.servlet.http.HttpServletRequest;
+
+@Component
+public class CustomRequestOriginParser implements RequestOriginParser {
+
+ @Override
+ public String parseOrigin(HttpServletRequest request) {
+ // 从 Header 中,获得请求来源
+ String origin = request.getHeader("s-user");
+ // 如果为空,给一个默认的
+ if (StringUtils.isEmpty(origin)) {
+ origin = "default";
+ }
+ return origin;
+ }
+
+}
diff --git a/labx-04/labx-04-sca-sentinel-nacos-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/web/GlobalExceptionHandler.java b/labx-04/labx-04-sca-sentinel-nacos-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/web/GlobalExceptionHandler.java
new file mode 100644
index 00000000..f60b2fe6
--- /dev/null
+++ b/labx-04/labx-04-sca-sentinel-nacos-provider/src/main/java/cn/iocoder/springcloudalibaba/labx04/sentineldemo/provider/web/GlobalExceptionHandler.java
@@ -0,0 +1,21 @@
+package cn.iocoder.springcloudalibaba.labx04.sentineldemo.provider.web;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.alibaba.fastjson.JSONObject;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@Component
+@ControllerAdvice(basePackages = "cn.iocoder.springcloudalibaba.labx04.sentineldemo.provider")
+public class GlobalExceptionHandler {
+
+ @ResponseBody
+ @ExceptionHandler(value = BlockException.class) // 因为这里是示例,所以暂时使用 JSONObject,实际项目最终定义一个 CommonResult。
+ public JSONObject blockExceptionHandler(BlockException blockException) {
+ return new JSONObject().fluentPut("code", 1024)
+ .fluentPut("msg", "请求被拦截,拦截类型为 " + blockException.getClass().getSimpleName());
+ }
+
+}
diff --git a/labx-04/labx-04-sca-sentinel-nacos-provider/src/main/resources/application.yaml b/labx-04/labx-04-sca-sentinel-nacos-provider/src/main/resources/application.yaml
new file mode 100644
index 00000000..c8f08422
--- /dev/null
+++ b/labx-04/labx-04-sca-sentinel-nacos-provider/src/main/resources/application.yaml
@@ -0,0 +1,26 @@
+spring:
+ application:
+ name: demo-provider
+
+ cloud:
+ # Sentinel 配置项,对应 SentinelProperties 配置属性类
+ sentinel:
+ enabled: true # 是否开启。默认为 true 开启
+ eager: true # 是否饥饿加载。默认为 false 关闭
+ transport:
+ dashboard: 127.0.0.1:7070 # Sentinel 控制台地址
+ filter:
+ url-patterns: /** # 拦截请求的地址。默认为 /*
+ # Sentinel 规则的数据源,是一个 Map 类型。key 为数据源名,可自定义;value 为数据源的具体配置
+ datasource:
+ ds1:
+ # 对应 FileDataSourceProperties 配置属性类
+ nacos:
+ server-addr: 127.0.0.1:8848
+ data-id: ${spring.application.name}-flow-rule
+# data-id: demo-application-flow-rule
+# data-id: demo-provider-flow-rule
+ namespace:
+ group-id: DEFAULT_GROUP
+ data-type: json
+ rule-type: FLOW
diff --git a/labx-04/pom.xml b/labx-04/pom.xml
index 1955f011..769af53c 100644
--- a/labx-04/pom.xml
+++ b/labx-04/pom.xml
@@ -13,6 +13,7 @@
pom
labx-04-sca-sentinel-demo01-provider
+ labx-04-sca-sentinel-nacos-provider