From f96c656852cc5a036645931b36ce478070ecaacf Mon Sep 17 00:00:00 2001
From: YunaiV <>
Date: Fri, 31 Jan 2020 11:26:37 +0800
Subject: [PATCH] =?UTF-8?q?sentinel=20=E4=BD=BF=E7=94=A8=20apollo=20?=
=?UTF-8?q?=E4=BD=9C=E4=B8=BA=E6=95=B0=E6=8D=AE=E6=BA=90=E7=A4=BA=E4=BE=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
lab-46/lab-46-sentinel-demo-apollo/pom.xml | 61 ++++++++++++++
.../lab46/sentineldemo/Application.java | 17 ++++
.../config/SentinelConfiguration.java | 56 +++++++++++++
.../config/SpringMvcConfiguration.java | 53 ++++++++++++
.../controller/DemoController.java | 82 +++++++++++++++++++
.../web/GlobalExceptionHandler.java | 17 ++++
.../src/main/resources/application.yaml | 6 ++
.../src/main/resources/sentinel.properties | 1 +
.../lab46/sentineldemo/Application.java | 2 +-
lab-46/pom.xml | 1 +
10 files changed, 295 insertions(+), 1 deletion(-)
create mode 100644 lab-46/lab-46-sentinel-demo-apollo/pom.xml
create mode 100644 lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/Application.java
create mode 100644 lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/config/SentinelConfiguration.java
create mode 100644 lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/config/SpringMvcConfiguration.java
create mode 100644 lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/controller/DemoController.java
create mode 100644 lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/web/GlobalExceptionHandler.java
create mode 100644 lab-46/lab-46-sentinel-demo-apollo/src/main/resources/application.yaml
create mode 100644 lab-46/lab-46-sentinel-demo-apollo/src/main/resources/sentinel.properties
diff --git a/lab-46/lab-46-sentinel-demo-apollo/pom.xml b/lab-46/lab-46-sentinel-demo-apollo/pom.xml
new file mode 100644
index 00000000..d44a37a7
--- /dev/null
+++ b/lab-46/lab-46-sentinel-demo-apollo/pom.xml
@@ -0,0 +1,61 @@
+
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.2.2.RELEASE
+
+
+ 4.0.0
+
+ lab-46-sentinel-demo-apollo
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+ com.alibaba.csp
+ sentinel-core
+ 1.7.1
+
+
+
+ com.alibaba.csp
+ sentinel-transport-simple-http
+ 1.7.1
+
+
+
+ com.alibaba.csp
+ sentinel-spring-webmvc-adapter
+ 1.7.1
+
+
+
+ com.alibaba.csp
+ sentinel-parameter-flow-control
+ 1.7.1
+
+
+
+ com.alibaba.csp
+ sentinel-annotation-aspectj
+ 1.7.1
+
+
+
+ com.alibaba.csp
+ sentinel-datasource-apollo
+ 1.7.1
+
+
+
+
diff --git a/lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/Application.java b/lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/Application.java
new file mode 100644
index 00000000..de707eb1
--- /dev/null
+++ b/lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/Application.java
@@ -0,0 +1,17 @@
+package cn.iocoder.springboot.lab46.sentineldemo;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+ public static void main(String[] args) {
+ // 设置系统属性 project.name,提供给 Sentinel 读取
+ System.setProperty("project.name", "demo-application");
+
+ // 启动 Spring Boot 应用
+ SpringApplication.run(Application.class, args);
+ }
+
+}
diff --git a/lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/config/SentinelConfiguration.java b/lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/config/SentinelConfiguration.java
new file mode 100644
index 00000000..8a22c930
--- /dev/null
+++ b/lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/config/SentinelConfiguration.java
@@ -0,0 +1,56 @@
+package cn.iocoder.springboot.lab46.sentineldemo.config;
+
+import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
+import com.alibaba.csp.sentinel.datasource.Converter;
+import com.alibaba.csp.sentinel.datasource.apollo.ApolloDataSource;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
+import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Arrays;
+import java.util.List;
+
+@Configuration
+public class SentinelConfiguration {
+
+ @Value("${spring.application.name}")
+ private String applicationName;
+
+ @Bean
+ public SentinelResourceAspect sentinelResourceAspect() {
+ return new SentinelResourceAspect();
+ }
+
+ @Bean
+ public ApolloDataSource apolloDataSource(ObjectMapper objectMapper) {
+ // Apollo 配置。这里先写死,推荐后面写到 application.yaml 配置文件中。
+ String appId = applicationName; // Apollo 项目编号。一般情况下,推荐和 spring.application.name 保持一致
+ String serverAddress = "http://localhost:8080"; // Apollo Meta 服务器地址
+ String namespace = "application"; // Apollo 命名空间
+ String flowRuleKey = "sentinel.flow-rule"; // Apollo 配置项的 KEY
+
+ // 创建 ApolloDataSource 对象
+ System.setProperty("app.id", appId);
+ System.setProperty("apollo.meta", serverAddress);
+ ApolloDataSource> apolloDataSource = new ApolloDataSource<>(namespace, flowRuleKey, "",
+ new Converter>() { // 转换器,将读取的 Apollo 配置,转换成 FlowRule 数组
+ @Override
+ public List convert(String value) {
+ try {
+ return Arrays.asList(objectMapper.readValue(value, FlowRule[].class));
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+
+ // 注册到 FlowRuleManager 中
+ FlowRuleManager.register2Property(apolloDataSource.getProperty());
+ return apolloDataSource;
+ }
+
+}
diff --git a/lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/config/SpringMvcConfiguration.java b/lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/config/SpringMvcConfiguration.java
new file mode 100644
index 00000000..c6d06427
--- /dev/null
+++ b/lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/config/SpringMvcConfiguration.java
@@ -0,0 +1,53 @@
+package cn.iocoder.springboot.lab46.sentineldemo.config;
+
+import com.alibaba.csp.sentinel.adapter.spring.webmvc.SentinelWebInterceptor;
+import com.alibaba.csp.sentinel.adapter.spring.webmvc.SentinelWebTotalInterceptor;
+import com.alibaba.csp.sentinel.adapter.spring.webmvc.config.SentinelWebMvcConfig;
+import com.alibaba.csp.sentinel.adapter.spring.webmvc.config.SentinelWebMvcTotalConfig;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class SpringMvcConfiguration implements WebMvcConfigurer {
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ // Add Sentinel interceptor
+// addSentinelWebTotalInterceptor(registry);
+ addSentinelWebInterceptor(registry);
+ }
+
+ private void addSentinelWebInterceptor(InterceptorRegistry registry) {
+ // 创建 SentinelWebMvcConfig 对象
+ SentinelWebMvcConfig config = new SentinelWebMvcConfig();
+ config.setHttpMethodSpecify(true); // 是否包含请求方法。即基于 URL 创建的资源,是否包含 Method。
+ // config.setBlockExceptionHandler(new DefaultBlockExceptionHandler()); // 设置 BlockException 处理器。
+// config.setOriginParser(new RequestOriginParser() { // 设置请求来源解析器。用于黑白名单控制功能。
+//
+// @Override
+// public String parseOrigin(HttpServletRequest request) {
+// // 从 Header 中,获得请求来源
+// String origin = request.getHeader("s-user");
+// // 如果为空,给一个默认的
+// if (StringUtils.isEmpty(origin)) {
+// origin = "default";
+// }
+// return origin;
+// }
+//
+// });
+
+ // 添加 SentinelWebInterceptor 拦截器
+ registry.addInterceptor(new SentinelWebInterceptor(config)).addPathPatterns("/**");
+ }
+
+ private void addSentinelWebTotalInterceptor(InterceptorRegistry registry) {
+ // 创建 SentinelWebMvcTotalConfig 对象
+ SentinelWebMvcTotalConfig config = new SentinelWebMvcTotalConfig();
+
+ // 添加 SentinelWebTotalInterceptor 拦截器
+ registry.addInterceptor(new SentinelWebTotalInterceptor(config)).addPathPatterns("/**");
+ }
+
+}
diff --git a/lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/controller/DemoController.java b/lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/controller/DemoController.java
new file mode 100644
index 00000000..950b0916
--- /dev/null
+++ b/lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/controller/DemoController.java
@@ -0,0 +1,82 @@
+package cn.iocoder.springboot.lab46.sentineldemo.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 {
+ // 访问资源
+ entry = SphU.entry("entry_demo");
+
+ // ... 执行业务逻辑
+
+ return "执行成功";
+ } catch (BlockException ex) {
+ return "被拒绝";
+ } finally {
+ // 释放资源
+ if (entry != null) {
+ entry.exit();
+ }
+ }
+ }
+
+ // 测试 @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/lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/web/GlobalExceptionHandler.java b/lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/web/GlobalExceptionHandler.java
new file mode 100644
index 00000000..21759025
--- /dev/null
+++ b/lab-46/lab-46-sentinel-demo-apollo/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/web/GlobalExceptionHandler.java
@@ -0,0 +1,17 @@
+package cn.iocoder.springboot.lab46.sentineldemo.web;
+
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+@ControllerAdvice(basePackages = "cn.iocoder.springboot.lab46.sentineldemo.controller")
+public class GlobalExceptionHandler {
+
+ @ResponseBody
+ @ExceptionHandler(value = BlockException.class)
+ public String blockExceptionHandler(BlockException blockException) {
+ return "请求过于频繁";
+ }
+
+}
diff --git a/lab-46/lab-46-sentinel-demo-apollo/src/main/resources/application.yaml b/lab-46/lab-46-sentinel-demo-apollo/src/main/resources/application.yaml
new file mode 100644
index 00000000..c33c2c66
--- /dev/null
+++ b/lab-46/lab-46-sentinel-demo-apollo/src/main/resources/application.yaml
@@ -0,0 +1,6 @@
+spring:
+ application:
+ name: demo-application
+
+server:
+ port: 18080 # 避免和 Apollo 使用到的 8080 端口冲突
diff --git a/lab-46/lab-46-sentinel-demo-apollo/src/main/resources/sentinel.properties b/lab-46/lab-46-sentinel-demo-apollo/src/main/resources/sentinel.properties
new file mode 100644
index 00000000..be3ba228
--- /dev/null
+++ b/lab-46/lab-46-sentinel-demo-apollo/src/main/resources/sentinel.properties
@@ -0,0 +1 @@
+csp.sentinel.dashboard.server=127.0.0.1:7070
diff --git a/lab-46/lab-46-sentinel-demo-nacos/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/Application.java b/lab-46/lab-46-sentinel-demo-nacos/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/Application.java
index e0e8b2d6..de707eb1 100644
--- a/lab-46/lab-46-sentinel-demo-nacos/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/Application.java
+++ b/lab-46/lab-46-sentinel-demo-nacos/src/main/java/cn/iocoder/springboot/lab46/sentineldemo/Application.java
@@ -8,7 +8,7 @@ public class Application {
public static void main(String[] args) {
// 设置系统属性 project.name,提供给 Sentinel 读取
- System.setProperty("project.name", "demo-application-nacos");
+ System.setProperty("project.name", "demo-application");
// 启动 Spring Boot 应用
SpringApplication.run(Application.class, args);
diff --git a/lab-46/pom.xml b/lab-46/pom.xml
index 2c491d16..b20fd68f 100644
--- a/lab-46/pom.xml
+++ b/lab-46/pom.xml
@@ -14,6 +14,7 @@
lab-46-sentinel-demo
lab-46-sentinel-demo-nacos
+ lab-46-sentinel-demo-apollo