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