Spring MVC 集成Servlet 3.0 AsyncContext异步请求异常分析
在调试Spring MVC 集成 Servlet 3.0的 AsyncContext 做异步处理时,碰到一个平时未注意到和较少会触发的怪异问题,结合调试结果和自己的猜想,对比研究了下源码来解释此问题的根本原因。
在调试Spring MVC 集成 Servlet 3.0的 AsyncContext 做异步处理时,碰到一个平时未注意到和较少会触发的怪异问题,结合调试结果和自己的猜想,对比研究了下源码来解释此问题的根本原因。
Servlet 和基于 Servlet 的容器(例如Tomcat)默认处理请求和处理业务是同一条线程,即有请求进来后,分配一条线程接收并处理请求,并继续执行业务处理,直到所有处理结束才完成响应,线程才会释放。这使得 Servlet 对业务方法的调用变成一种阻塞调用,效率较低。
Servlet3.0 提供了AsyncContex 来异步处理请求,将请求线程与业务处理线程分离。
系统提供对外接口或公用方法时,通常需要对入参校验,即直接在接口入口层就进行校验,不让非法参数流入到业务层导致异常,确保系统的健壮性。。
数据校验分客户端校验和服务端校验,客户端校验主要在页面通过JavaScript来实现,过滤正常用户的误操作,仅做初步过滤;服务端校验是整个应用阻止非法数据的最后防线,客户端校验绝不能替代服务端的校验,客户端校验可以降低服务器的负载。
整理这篇文章由两个因素引发:
一个是参与的微服务项目涉及到权限管理应用到了 HandlerMapping ,使用自定义注解,自动或手动拿到各个微服务所有自定义的 Controller RequestMapping(URI)同步到权限管理模块。
二是开发的项目报了异常,打印的异常信息比较有意思,就跟踪源码查到信息也是来自于 HandlerMapping,这些信息可以自己获取后应用在拦截器或 Controller 层的 AOP 中。
备注:已使用 AOP 拿到类似到源码抛出的打印的异常信息,但没有源码抛出的异常信息完美优雅。
Spring MVC API 接口响应的消息体最好统一结构,便于前端识别和规范。
Servlet 3.0+ 异步方法实现服务端消息推送是通过使用定时任务,定时的让控制器从另外一个线程返回一个DeferedResult
并推送给客户端。而更新DeferedResult
是在使用@Scheduled
定时任务注解的方法里执行的。
Web 项目中,浏览器与服务器是通过请求和响应来实现功能功能交互的,当服务端出现新的信息需要让前端知道时,就需要用到服务器推送技术。
服务端推送技术有基于SSE
(Server Send Event 服务端发送事件)的服务器端推送,该方式需要浏览器支持,而目前主流浏览器最近版本基本都支持;基于Servlet 3.0+
的异步方法特性;WebSocket
双向通信技术。
通常会在 @Controller
注解作用的类的方法上使用@ExceptionHandler,@ModelAttribute,@InitBinder
来处理异常或初始化绑定,这三个注解对所用使用了 @RequestMapping
注解的控制器内的方法有效。
如果希望此类方法在全局范围内(跨控制器)应用,则可以在带有 @ControllerAdvice
或 @RestControllerAdvice
注解的类中声明它们这三个注解。
@ControllerAdvice
用于声明一个 控制器 建言,作用在类上,可以将控制器的全局配置统一放置在该注解作用的类里,结合在方法上使用 @ExceptionHandler
注解,就能实现全局的异常控制。
文件上传可以说是项目中最常用的功能。
Spring MVC 为文件上传提供了直接的支持,Spring MVC 提供了一个文件上传的解析类CommonsMultipartResolver
,即插即用(在XML文件装配下),该类依赖了Apache Commons FileUpload
技术,所以需要导入commons-fileupload.jar
和commons-io.jar
两个包。
上传文件,必须将表单的method
设置为post
,并将enctype
设置为multipart/form-data
,浏览器才会把文件二进制数据发给服务器。
拦截器是 Web 项目很重要和常用的功能,如对用户权限验证,判断用户是否已登录等。
SpringMVC 中的拦截器通过实现HanderInterceptor
接口来完成,或继承抽象类HandlerInterceptorAdapter
,重写里面的方法来完成。