spring cloud alibaba整合sentinel之webmvc拦截器方式源码简析
程序员文章站
2022-03-26 19:27:10
spring cloud alibaba提供的Sentinel支持方式如下:1、使用webmvc方式,即使用SentinelWebInterceptor拦截器2、对Feign的支持,需开启feign.sentinel.enabled参数3、对RestTemplate的支持,使用@SentinelRestTemplate注解本文主要说明使用webmvc方式的源码简析。Spring Cloud Alib...
spring cloud alibaba
提供的Sentinel
支持方式如下:
- 使用webmvc方式,即使用
SentinelWebInterceptor
拦截器 - 对Feign的支持,需开启
feign.sentinel.enabled
参数 - 对RestTemplate的支持,使用
@SentinelRestTemplate
注解
本文主要说明使用webmvc方式的源码简析,看本文前需要对Sentinel
组件有一定了解。项目依赖的spring cloud的版本信息如下:
Spring Cloud Alibaba Version | Sentinel Version | Nacos Version |
---|---|---|
2.2.3.RELEASE | 1.8.0 | 1.3.3 |
涉及到的关键jar:spring-cloud-starter-alibaba-sentinel-2.2.3.RELEASE.jar
、sentinel-spring-webmvc-adapter-1.8.0.jar
1.程序加载入口SentinelWebAutoConfiguration
按照套路,分析的入口肯定starter的某一个AutoConfiguration里。
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnProperty(name = "spring.cloud.sentinel.enabled", matchIfMissing = true)
@ConditionalOnClass(SentinelWebInterceptor.class)
@EnableConfigurationProperties(SentinelProperties.class)
public class SentinelWebAutoConfiguration implements WebMvcConfigurer {
private static final Logger log = LoggerFactory
.getLogger(SentinelWebAutoConfiguration.class);
@Autowired
private SentinelProperties properties;
@Autowired
private Optional<UrlCleaner> urlCleanerOptional;
@Autowired
private Optional<BlockExceptionHandler> blockExceptionHandlerOptional;
@Autowired
private Optional<RequestOriginParser> requestOriginParserOptional;
@Autowired
private Optional<SentinelWebInterceptor> sentinelWebInterceptorOptional;
//将拦截器添加到spring mvc的配置中
@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());
}
//构建拦截器对象,SentinelWebMvcConfig对象的创建在后面的代码里分析
@Bean
@ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled",
matchIfMissing = true)
public SentinelWebInterceptor sentinelWebInterceptor(
SentinelWebMvcConfig sentinelWebMvcConfig) {
return new SentinelWebInterceptor(sentinelWebMvcConfig);
}
//创建SentinelWebMvcConfig对象,为创建SentinelWebInterceptor提供参数配置
@Bean
@ConditionalOnProperty(name = "spring.cloud.sentinel.filter.enabled",
matchIfMissing = true)
public SentinelWebMvcConfig sentinelWebMvcConfig() {
SentinelWebMvcConfig sentinelWebMvcConfig = new SentinelWebMvcConfig();
sentinelWebMvcConfig.setHttpMethodSpecify(properties.getHttpMethodSpecify());
sentinelWebMvcConfig.setWebContextUnify(properties.getWebContextUnify());
if (blockExceptionHandlerOptional.isPresent()) {
blockExceptionHandlerOptional
.ifPresent(sentinelWebMvcConfig::setBlockExceptionHandler);
}
else {
if (StringUtils.hasText(properties.getBlockPage())) {
sentinelWebMvcConfig.setBlockExceptionHandler(((request, response,
e) -> response.sendRedirect(properties.getBlockPage())));
}
else {
sentinelWebMvcConfig
.setBlockExceptionHandler(new DefaultBlockExceptionHandler());
}
}
urlCleanerOptional.ifPresent(sentinelWebMvcConfig::setUrlCleaner);
requestOriginParserOptional.ifPresent(sentinelWebMvcConfig::setOriginParser);
return sentinelWebMvcConfig;
}
}
同过sentinelWebInterceptor()
和 sentinelWebMvcConfig()
方法,我们可以得到以下有用的信息:
- 通过
sentinelWebInterceptor()
方法上的注解参数spring.cloud.sentinel.filter.enabled
可以知道引入sentinel-spring-webmvc-adapter-1.8.0.jar
后默认就开启了使用SentinelWebInterceptor
来处理 -
UrlCleaner
为自动注入,如果想自定义UrlCleaner
,只需自己写一个UrlCleaner
接口实现类,并添加到Spring IOC 容器中即可 -
BlockExceptionHandler
为自动注入,如果不想使用默认的DefaultBlockExceptionHandler
,只需自己写一个BlockExceptionHandler
接口实现类,并添加到Spring IOC 容器中即可 - 可以采用和3类型的方式自定义
RequestOriginParser
2.重点配置类SentinelProperties的配置
同过addInterceptors()
方法可以看到,只针对filter提供如下配置:
1、通过spring.cloud.sentinel.filter的配置
spring:
cloud:
sentinel:
filter:
#配置需要拦截的URL(默认"/**")
url-patterns:
- '/userconfig/**'
- '/nacosconfig/**'
#拦截器的order(默认最高优先级-2147483648)
order:-123
2、SentinelProperties还提供很多常用的配置,跟SentinelWebMvcConfig相关的还有:
spring:
cloud:
sentinel:
#如果针对同一URL资源需要区分是Post还是Get请求可以将参数设置为true
http-method-specify:true
webContextUnify:true
3.拦截器SentinelWebInterceptor源码简析
public class SentinelWebInterceptor extends AbstractSentinelInterceptor {
private final SentinelWebMvcConfig config;
public SentinelWebInterceptor() {
this(new SentinelWebMvcConfig());
}
public SentinelWebInterceptor(SentinelWebMvcConfig config) {
super(config);
if (config == null) {
// Use the default config by default.
this.config = new SentinelWebMvcConfig();
} else {
this.config = config;
}
}
@Override
protected String getResourceName(HttpServletRequest request) {
// Resolve the Spring Web URL pattern from the request attribute.
Object resourceNameObject = request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
if (resourceNameObject == null || !(resourceNameObject instanceof String)) {
return null;
}
String resourceName = (String) resourceNameObject;
UrlCleaner urlCleaner = config.getUrlCleaner();
if (urlCleaner != null) {
resourceName = urlCleaner.clean(resourceName);
}
// Add method specification if necessary
if (StringUtil.isNotEmpty(resourceName) && config.isHttpMethodSpecify()) {
resourceName = request.getMethod().toUpperCase() + ":" + resourceName;
}
return resourceName;
}
@Override
protected String getContextName(HttpServletRequest request) {
if (config.isWebContextUnify()) {
return super.getContextName(request);
}
return getResourceName(request);
}
}
//AbstractSentinelInterceptor类的中的方法
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
try {
String resourceName = getResourceName(request);
if (StringUtil.isEmpty(resourceName)) {
return true;
}
if (increaseReferece(request, this.baseWebMvcConfig.getRequestRefName(), 1) != 1) {
return true;
}
// Parse the request origin using registered origin parser.
String origin = parseOrigin(request);
String contextName = getContextName(request);
ContextUtil.enter(contextName, origin);
Entry entry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.IN);
request.setAttribute(baseWebMvcConfig.getRequestAttributeName(), entry);
return true;
} catch (BlockException e) {
try {
handleBlockException(request, response, e);
} finally {
ContextUtil.exit();
}
return false;
}
}
该类业务逻辑很简单。主要业务如下:
- 解析请求资源路径,支持通过我们自定义的
UrlCleaner
来对URL资源进行清洗,一般用于变量在url路径的restful形式的url,如:/getuser/123 - 在拦截器的preHandle方法中对URL使用
SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.IN)
进行保护
本文地址:https://blog.csdn.net/mapleleafforest/article/details/111033992