@startuml
interface HandlerInterceptor{
+ boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler);
+ void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,ModelAndView modelAndView);
+ void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,Exception ex);
}
interface HandlerMapping{}
class HandlerExecutionChain{
- Object handler;
- final List<HandlerInterceptor> interceptorList;
- int interceptorIndex
+ HandlerExecutionChain(Object handler, List<HandlerInterceptor> interceptorList)
~ boolean applyPreHandler(HttpservletRequestt,HttpServletResponse response);
~ boolean applyPostHandle(HttpservletRequestt,HttpServletResponse response);
~ boolean triggerAfterCompletion(HttpservletRequestt,HttpServletResponse response);
}
interface HandlerAdapter{
~ ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler);
}
interface WebMvcConfigurer {
+ void addInterceptors(InterceptorRegistry registry);
}
@enduml
1 HandlerInterceptor
springf-webmvc-5.3.9.jar org.springframework.web.servlet
工作流接口,它允许定制化的handler执行链。应用可以注册任何数量的已经存在的或定制的拦截器给特定组的handlers,目的是在不必修改handler实现的情况下来增加前处理行为。
?handler指的是什么?————指方法吗?
一个handler拦截器会在合适的HandlerAdapter触发handler执行之前被调用。这个机制可以被用在很多前处理方面。例如权限校验,或通用行为语言或主题的变换。他的主要目的就是提取重复的hanler代码。
在异步处理的场景,hanlder也许会被执行在一个分离的线程,与此同时,主线程没有渲染或执行postHandle
或afterCompletion
回调函数。当并行的handler 执行完成,请求会被分配回来,为了执行渲染模型,并且这个contract的所有方法会被再触发一遍。异步的请看AsyncHandlerInterceptor
。
典型的情况就是 每个HandlerMapping Bean 都会定义一个拦截器链。为了能够应用一个特定的拦截器链给一组特定的Handler,我们需要给一个HandlerMapping bean 匹配想要的handler。拦截器被定义成bean保存在上下文中,通过interceptors变量来被匹配的bean引用。
HandlerInterceptor
和Servlet Filter
基本相似。但是相较于后者,HandlerInterceptor他有一个前处理的选项:禁止执行Hander本身及其后续的定制化后处理。Filters更强力,例如他们允许调换链上的请求和响应。需要强调的是Filter在web.xml
中配置。拦截器在上下文中配置。
作为一个基本的指导,细粒度的handler相关的任务最好交给HanlerInterceptor实现,特别是分离handler通用代码的功能或校验权限。另一方面,Filter适合request和view内容的处理,例如multipartforms 和 GZIP的压缩。当一个人需要匹配filter给特定content(e.g. 图片) 或匹配给所有request时。
2 HandlerMapping
给定义了请求和处理器之间的映射关系的对象来实现的接口
HanlerMapping 的实现可以支持被匹配好的拦截器,但不是必须的。一个Handler总是被HandlerExecutionChain
实例包装起来,可选的选项还有HandlerInterceptor
实例。DispatcherServlet会先调用HandlerInterceptor的preHandler
方法,最终调用hanler自己的方法,如果所有的preHandle都返回true.
将映射参数化的能力是MVC framework 的强力的不同寻常的能力。例如,它能够基于session 状态,cookie状态或其他变量 来写出一个定制化的mapping.其他框架没有这么灵活。
3 HandlerExecutionChain
Handler execution chain ,包含了handler,handler拦截器
4 HandlerAdapter
MVC 框架的SPI,允许将核心的MVC工作流参数化
SPI SPI是一种回调的思想,回调是指我们在使用api时,我们可以向api传入一个类或者方法,api在合适的时间调用类或者方法。SPI是在一些通用的标准中,为标准的实现产商提供的扩展点。标准在上层提供API,API内部使用了SPI,当API被客户使用时,会动态得从当前运行的classpath中寻找该SPI的实现,然后使用该SPI的实现来完成API的功能。
处理请求的每种类型的handler一定要实现的接口。这个接口是用来让DispathcerServlet能够无限扩展。DispatcherServlet访问所有的Handler通过这个接口,意味着他不包含特定handler类型的代码。
值得注意的是,handler的类型是Object.目的是能够让其他框架的handler整合进框架二不用特定编码,也让注解驱动的handler对象不用遵从特定的Java接口。
这个接口的目的不是给应用开发者用的。给框架扩展者使用的。
5 DispatcherServlet
http 请求的中央调度器,比如 给web ui的controllers或基于http的远程服务的暴露接口。调度给已注册的handlers来处理网页请求,提供便利的匹配和异常处理。
这个servlet非常灵活,配合合适的适配器,它能够被任何workflow使用。它提供以下的功能,这些功能将dispatcherservlet 与其他请求驱动的webMVC框架区分开:
- 基于javaBean配置机制
- 它可以使用任何
HandlerMapping
的实现,来控制requests到某个handler的路由。默认的实现是org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
和org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.
- 他可以使用任何
HandlerAdapter
。借此它能够使用任何的handler接口。默认的适配器是org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
和org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
这两个适配器适配的是org.springframework.web.HttpRequestHandler
和org.springframework.web.servlet.mvc.Controller
的接口。默认的org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
也会被注册。handlerAdapter作为一个bean,会被注册在应用上下文中 - 异常处理是通过
HandlerExceptionResolver
,例如将特定异常map到特殊的页面。默认的是org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver
和org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver
和org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver
- View 处理,multipart请求处理,locale处理和theme 处理略
6 WebMvcConfigurer
定义回调方法来定制化java-based 配置Spring MVC 。被@EnableWebMvc注解的配置类可以实现这个接口来被回调并且得到定制化配置的机会。
7 DispacherServlet顺序图
@startuml
Client->DispatcherServlet++:doService
note right
暴露了DispatcherServlet特有的属性,并且将任务分给`doDispatch`方法来做实际的分配任务.
end note
DispatcherServlet->DispatcherServlet++:doDispatch()
note right
通过按顺序调用Servlet的HanderMapping,能够获得handler.通过Servlet中的HanderAdaptor List 中支持handler的class类型的adapter,来获取对应的handlerAdaptor.
所有http 方法由改函数处理。由handlerAdapters或handlers 来决定哪个方法是可接受的。
end note
DispatcherServlet->DispatcherServlet++:getHandler()
loop 遍历DispatcherServlet中的HandlerMapping list
note right
返回这个请求的处理程序和任何拦截程序。可以根据请求的URL、会话状态或实现类选择的任何因素进行选择。
返回的HandlerExecutionChain包含一个处理程序对象,甚至不是一个标签接口,所以处理程序不会受到任何限制。例如,可以写一个HandlerAdapter来允许使用另一个框架的处理程序对象。
end note
DispatcherServlet->HandlerMapping++:getHandler()
return HandlerExecutionChain
end
return HandlerExecutionChain
DispatcherServlet->DispatcherServlet++:getHandlerAdapter()
loop 遍历DispatcherServlet中的HandlerAdapter list
note right
返回handler对应的HandlerAdapter
end note
DispatcherServlet->HandlerAdapter++:support()
return boolean
end
return HandlerAdapter
DispatcherServlet->HandlerExecutionChain++:applyPreHandle()
note right
应用所有的拦截器的preHandle()方法
end note
loop 遍历HandlerExecutionChain中的HandlerInterceptor
HandlerExecutionChain->HandlerInterceptor++:preHandle()
return
end
return
DispatcherServlet-> HandlerAdapter++:handle()
note right
处理请求
end note
return
note right
一般请求里面将hanlder->HandlerMethod->ServletInvocableHandlerMethod#invokeAndHandle();
里面还有参数绑定之类的
end note
DispatcherServlet->HandlerExecutionChain++:applyPostHandle()
note right
应用所有的拦截器的postHandle()方法
end note
loop 遍历HandlerExecutionChain中的HandlerInterceptor
HandlerExecutionChain->HandlerInterceptor++:postHandle()
return
end
return
DispatcherServlet->DispatcherServlet++:processDispatchResult()
note right
处理异常或ModelAndView
end note
return
DispatcherServlet->HandlerExecutionChain++:triggerAfterCompletion()
note right
应用所有的拦截器的afterCompletion()方法
end note
loop 遍历HandlerExecutionChain中的HandlerInterceptor
HandlerExecutionChain->HandlerInterceptor++:afterCompletion()
return
end
return
return
return
@enduml
-
请求命中的
HanderMapping
是RequestMappingHandlerMapping
,返回的HandlerExecutionChain
中的Handler是Controller#method()
,还有三个拦截器ResourceUrlProviderExposingInterceptor
,ConversionServiceExposingInterceptor
和LongTaskTimingHandlerInterceptor
-
根据Handler查找Adapter 命中的是
RequestMappingHandlerAdapter