示例项目
示例项目 GitHub:https://github.com/leo1604270786/hello-sentinel
细节可以查看我的这篇文章 SpringCloud 整合 Sentinel 并连接 Nacos 改造后的控制台
pom.xml :
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>top.zysite</groupId>
<artifactId>hello-sentinel</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>hello-sentinel</name>
<description>Demo project for Spring Boot</description>
<packaging>pom</packaging>
<modules>
<module>hello-sentinel-gateway</module>
<module>hello-sentinel-normal</module>
</modules>
<properties>
<spring-cloud.version>Hoxton.SR5</spring-cloud.version>
<admin-starter-server.version>2.2.3</admin-starter-server.version>
<spring-cloud-alibaba.version>2.2.0.RELEASE</spring-cloud-alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<!--Spring Cloud 相关依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--集成SpringBoot Admin监控-->
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>${admin-starter-server.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>spring</id>
<url>https://maven.aliyun.com/repository/spring</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project>
原因
SpringCloud 整合 Sentinel 会通过SentinelWebAutoConfiguration
自动配置类来对 Sentinel 进行配置,其中就包括注册 SentinelWebInterceptor 拦截器,来拦截 Web 请求,并且将 url 采集成资源,之后会在 sentinel-dashboard 中的簇点链路
中展示,SentinelWebAutoConfiguration
部分源码如下:
@Override
public void addInterceptors(InterceptorRegistry registry) {
if (!sentinelWebInterceptorOptional.isPresent()) {
return;
}
SentinelProperties.Filter filterConfig = properties.getFilter();
registry.addInterceptor(sentinelWebInterceptorOptional.get())
.order(filterConfig.getOrder())
.addPathPatterns(filterConfig.getUrlPatterns());
log.info(
"[Sentinel Starter] register SentinelWebInterceptor with urlPatterns: {}.",
filterConfig.getUrlPatterns());
}
在启动项目是可以看到下面这条日志:
2021-05-18 11:30:04.802 INFO 27797 --- [ main] c.a.c.s.SentinelWebAutoConfiguration : [Sentinel Starter] register SentinelWebInterceptor with urlPatterns: [/*].
可以看到,注册的拦截器拦截的 url 模式串 为/*
。
也可以通过查看SentinelProperties.Filter
类源码看到:
public static class Filter {
/**
* SentinelWebInterceptor order, will be register to InterceptorRegistry.
*/
private int order = Ordered.HIGHEST_PRECEDENCE;
/**
* URL pattern for SentinelWebInterceptor, default is /*.
*/
private List<String> urlPatterns = Arrays.asList("/*");
/**
* Enable to instance
* {@link com.alibaba.csp.sentinel.adapter.spring.webmvc.SentinelWebInterceptor}.
*/
private boolean enabled = true;
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
public List<String> getUrlPatterns() {
return urlPatterns;
}
public void setUrlPatterns(List<String> urlPatterns) {
this.urlPatterns = urlPatterns;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
在没有添加@SentinelResource
注解的情况下该模式串就会导致 Sentinel 只会拦截接口层级为 1 的 url。
如,下面只有/hello/sentinel
(添加了注解)、param
可以在 sentinel-dashboard 中的簇点链路
中展示,而/hello/degrade
不会展示,实时监控也看不到:
@RestController
public class HelloController {
@SentinelResource(value = "hello", fallback = "sentinelFallback")
@GetMapping("/hello/sentinel")
public String sentinel(){
return "hello sentinel";
}
// @SentinelResource(value = "degrade", fallback = "sentinelFallback")
@GetMapping("/hello/degrade")
public String degrade(){
//测试降级
if(new Random().nextInt() % 2 == 0) {
return "hello degrade";
} else {
throw new RuntimeException("RuntimeException");
}
}
@GetMapping("param")
public String paramFlowRule(String param1, Integer param2) {
return "paramFlowRule";
}
public String sentinelFallback() {
return "hello fallback";
}
}
注:以上源码都是在 spring-cloud-alibaba-dependencies 版本为 2.2.0.RELEASE 的情况下。
解决方案
添加配置
在 hello-sentinel-normal
和hello-sentinel-gateway
模块的配置文件application.yml
中添加以下配置:
spring:
cloud:
sentinel:
filter:
url-patterns: /**
重新启动即可在 sentinel-dashboard 中的簇点链路
中展示所有 url。
修改版本
将 spring-cloud-alibaba-dependencies 版本改为 2.2.4.RELEASE
<spring-cloud-alibaba.version>2.2.4.RELEASE</spring-cloud-alibaba.version>
可以在 2.2.4.RELEASE 版本中,查看SentinelProperties.Filter
类源码,url 模式串已经改为了/**
,不需要修改配置了:
public static class Filter {
/**
* SentinelWebInterceptor order, will be register to InterceptorRegistry.
*/
private int order = Ordered.HIGHEST_PRECEDENCE;
/**
* URL pattern for SentinelWebInterceptor, default is /**.
*/
private List<String> urlPatterns = Arrays.asList("/**");
/**
* Enable to instance
* {@link com.alibaba.csp.sentinel.adapter.spring.webmvc.SentinelWebInterceptor}.
*/
private boolean enabled = true;
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
public List<String> getUrlPatterns() {
return urlPatterns;
}
public void setUrlPatterns(List<String> urlPatterns) {
this.urlPatterns = urlPatterns;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
经测试,在 2.2.1.RELEASE 中该问题已经修复了,只需要将版本改为 2.2.1.RELEASE 或之后的版本即可。