龙空技术网

深度解析微服务高并发:适配SpringMVC框架适配模块及实现原理

程序员高级码农II 82

前言:

现在各位老铁们对“aspnetmvcupdate”可能比较关怀,大家都想要知道一些“aspnetmvcupdate”的相关知识。那么小编同时在网上搜集了一些有关“aspnetmvcupdate””的相关文章,希望你们能喜欢,朋友们一起来了解一下吧!

适配主流框架

如果不借助Sentinel提供的适配主流框架的模块,则在使用Sentinel时需要借助try-catchfinally将要保护的资源(方法或代码块)包起来,在目标方法或代码块执行之前,调用ContextUtil#enter方法及SphU#entry方法;在抛出异常时,如果非BlockException异常需要调用Tracer#trace方法统计异常指标,则在finally中需要调用SphU#entry方法返回的Entry实例的exit方法,以及ContextUtil#exit方法。

为了节省这些步骤,Sentinel提供了对主流框架的适配,如适配Spring MVC、WebFlux、Dubbo、APIGateway等框架,在Sentinel源码之外,Alibaba的spring-cloud-starter-alibabasentinel也为Sentinel提供了与OpenFeign框架整合的支持。

本篇内容主要包括以下几个方面。

• 适配Spring MVC框架。

• 适配OpenFeign框架。

• 适配Dubbo框架。

• 注解切面。

适配Spring MVC框架

Spring MVC框架是目前使用最多的一个Web框架(用Java语言编写),而Sentinel提供了与Spring MVC框架整合使用的适配模块。

本节将介绍如何使用Spring MVC适配模块并分析其实现原理。

使用步骤

要使用Sentinel提供的SpringMVC适配模块,只需要在项目中添加sentinel-springwebmvc-adapter模块的依赖即可,借助WebMvcConfigurer将SentinelWebInterceptor注册到Spring MVC框架中,步骤如下。

第一步,在项目中添加Spring MVC适配模块的依赖,代码如下。

第二步,编写WebMvcConfigurer,在addInterceptors方法中注入SentinelWebInterceptor,代码如下。

在创建SentinelWebInterceptor时,可以为SentinelWebInterceptor添加配置,使用SentinelWebMvcConfig封装这些配置。• setBlockExceptionHandler:配置BlockException处理器,如果不想配置BlockException处理器,则可以在Spring MVC的全局异常处理器中处理BlockException。

• setOriginParser:注册调用来源(origin)解析器,例如,从请求头中获取S-user参数的值作为调用来源名称,在向下游服务发起请求时在请求头写入S-user参数。

• setHttpMethodSpecify:是否需要给资源名称加上HttpMethod前缀,例如,对于GET接口/hello,如果将httpMethodSpecify配置为false,则资源名称为/hello,否则资源名称为GET:/hello。

适配原理

Sentinel适配Spring MVC框架是借助Spring MVC框架提供的方法拦截器实现的,通过方法拦截器在目标方法被调用之前、调用之后及发生异常时,分别调用ContextUtil#enter方法、SphU#entry方法、Tracer#trace方法、Entry#exit方法和ContextUtil#exit方法。

Spring MVC框架的方法拦截器(HandlerInterceptor)的定义如下。

HandlerInterceptor在DispatcherServlet#doDispatch方法中被调用,每个方法的调用时机如

下。

• preHandle:在调用接口方法之前被调用。

• postHandle:在接口方法执行完成并返回ModelAndView时被调用。

•afterCompletion:在接口方法执行完成时被调用,无论执行成功或发生异常都会被调用。

因此,Sentinel可以借助HandlerInterceptor与SpringMVC框架整合,在HandlerInterceptor#preHandle方法中调用ContextUtil#enter方法及SphU#entry方法,在afterCompletion方法中根据方法参数ex是否为空来处理异常情况,并且完成Entry#exit方法及ContextUtil#exit方法的调用。

SentinelWebInterceptor是AbstractSentinelInterceptor的子类,而preHandle方法与afterCompletion方法在父类中实现,其自身只实现父类定义的一个获取资源名称的抽象方法,即getResourceName方法。getResourceName方法的源码如下。

资源名称的生成过程如下。

① 从HttpServletRequest参数的属性中获取HandlerMapping匹配的URL。

② 如果UrlCleaner不为空,则调用UrlCleaner的clean方法,该方法可将多个接口合并为一个接口。

③ 根据SentinelWebMvcConfig配置对象判断是否需要添加HttpMethod前缀,如果需要,则给资源名称拼接前缀。

提示:有些接口的名称形如“/hello/{name}”,如果直接从HttpServletRequest参数中获取请求路径,则每个请求获取的URL可能会不同,所以需要从HandlerMapping属性中获取。

UrlCleaner的clean方法可将多个接口合并为一个接口,例如,若借助UrlCleaner将接口/user/create、/user/del和/user/update都改为/user/**,则可以实现3个接口使用同一个限流规则。一般来说,不建议添加HttpMethod前缀,因为如果接口使用@RequestMapping注解声明,那么想对该接口限流就需要配置多个限流规则。旧项目大多使用@RequestMapping注解声明接口方法。例如,对于接口/user/create,用户可能需要为此接口配置GET:/user/create、POST:/user/create等多个资源的限流规则。

由于AbstractSentinelInterceptor的源码较多,因此分步骤分析。

AbstractSentinelInterceptor#preHandle方法的源码如下。

① 获取资源名称。

② 调用OriginParser#parseOrigin方法解析调用来源,如从请求头中获取S-user参数的值。

③ 调用ContextUtil#enter方法,调用链入口名称为sentinel_spring_web_context。

④ 调用SphU#entry方法,资源类型为COMMON_WEB,流量类型为IN。

⑤ 将SphU#entry方法返回的Entry实例放入HttpServletRequest参数的属性表中,方便在AbstractSentinelInterceptor#afterCompletion方法中取出。

⑥ 如果抛出BlockException,则说明当前请求被拒绝,需要调用handleBlockException方

法处理BlockException。

AbstractSentinelInterceptor#handleBlockException方法的源码如下。

AbstractSentinelInterceptor#handleBlockException方法实现的功能:若SentinelWebMvcConfig配置了BlockExceptionHandler,则调用BlockExceptionHandler#handle方法处理BlockException,否则将抛出BlockException,并由全局处理器处理。

AbstractSentinelInterceptor#afterCompletion方法的源码如下。

① 从HttpServletRequest参数的属性表中获取preHandle方法中的Entry实例。

② 调用AbstractSentinelInterceptor#traceExceptionAndExit方法。

③ 调用ContextUtil#exit方法。

AbstractSentinelInterceptor#traceExceptionAndExit方法的源码如下。

AbstractSentinelInterceptor#traceExceptionAndExit方法实现的功能:当方法执行抛出异常时,调用Tracer#traceEntry方法统计异常指标数据。

本文给大家讲解的内容是深度解析微服务高并发适配主流框架:适配Spring MVC框架下篇文章给大家讲解的内容是深度解析微服务高并发适配主流框架:适配OpenFeign框架觉得文章不错的话,可以点赞关注转发一下哈~感谢大家的支持

标签: #aspnetmvcupdate