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