mirror of
https://gitee.com/yudaocode/SpringBoot-Labs.git
synced 2026-09-03 05:53:54 +08:00
sentinel 使用 apollo 作为数据源示例
This commit is contained in:
61
lab-46/lab-46-sentinel-demo-apollo/pom.xml
Normal file
61
lab-46/lab-46-sentinel-demo-apollo/pom.xml
Normal file
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.2.2.RELEASE</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>lab-46-sentinel-demo-apollo</artifactId>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- 实现对 SpringMVC 的自动化配置 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Sentinel 核心库 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-core</artifactId>
|
||||
<version>1.7.1</version>
|
||||
</dependency>
|
||||
<!-- Sentinel 接入控制台 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-transport-simple-http</artifactId>
|
||||
<version>1.7.1</version>
|
||||
</dependency>
|
||||
<!-- Sentinel 对 SpringMVC 的支持 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-spring-webmvc-adapter</artifactId>
|
||||
<version>1.7.1</version>
|
||||
</dependency>
|
||||
<!-- Sentinel 对【热点参数限流】的支持 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-parameter-flow-control</artifactId>
|
||||
<version>1.7.1</version>
|
||||
</dependency>
|
||||
<!-- Sentinel 对 Spring AOP 的拓展 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-annotation-aspectj</artifactId>
|
||||
<version>1.7.1</version>
|
||||
</dependency>
|
||||
<!-- Sentinel 对 Apollo 作为数据源的支持 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.csp</groupId>
|
||||
<artifactId>sentinel-datasource-apollo</artifactId>
|
||||
<version>1.7.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<List<FlowRule>> apolloDataSource = new ApolloDataSource<>(namespace, flowRuleKey, "",
|
||||
new Converter<String, List<FlowRule>>() { // 转换器,将读取的 Apollo 配置,转换成 FlowRule 数组
|
||||
@Override
|
||||
public List<FlowRule> 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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("/**");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 "请求过于频繁";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
spring:
|
||||
application:
|
||||
name: demo-application
|
||||
|
||||
server:
|
||||
port: 18080 # 避免和 Apollo 使用到的 8080 端口冲突
|
||||
@@ -0,0 +1 @@
|
||||
csp.sentinel.dashboard.server=127.0.0.1:7070
|
||||
@@ -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);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
<modules>
|
||||
<module>lab-46-sentinel-demo</module>
|
||||
<module>lab-46-sentinel-demo-nacos</module>
|
||||
<module>lab-46-sentinel-demo-apollo</module>
|
||||
</modules>
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user