一,核心流程
- 第一步:发起请求到前端控制器(
DispatcherServlet
)中的doDispatch
方法,然后委托给doDispatch
方法进行处理。 - 第二步:之后会请求
getHandler
方法,通过HandlerMapping
查找Handler
(根据配置、注解进行查找) - 第三步:查找到
Handler
之后,会把请求封装成HandlerExecutionChain
对象(包含一个Handler
处理器(页面控制器)对象,多个HandlerInterceptor
拦截器对象)并返回。 - 第四步:然后通过
getHandlerAdapter
方法获取支持处理这种handler
的处理器适配器HandlerAdapter
。 - 第五步:获取到的处理器适配器
HandlerAdapter
,将会根据适配的结果去执行Handler,通常会是由RequestMappingHandlerAdapter#handleInternal
进行执行。 - 第六步:
Handler
执行完成给适配器返回ModelAndView
,这里Handler
执行的通常是我们自己编写的controller
实现。 - 第七步:处理器适配器向前端控制器返回
ModelAndView
(ModelAndView
是springmvc框架的一个底层对象,包括 Model和view) - 第八步:前端控制器请求视图解析器去进行视图解析,通过这种策略很容易更换其他视图技术,比如thymeleaf、json等,只需要更改视图解析器即可
- 第九步:视图解析器向前端控制器返回View
- 第十步:前端控制器进行视图渲染 (视图渲染将模型数据(在ModelAndView对象中)填充到request域)
- 第十一步:前端控制器向用户响应结果
二,核心组件
1,DispatcherServlet
DispatcherServlet
是Spring MVC框架的中央处理器,它负责拦截所有请求,并分发到各控制器;同时提供其他web应用开发所需要的功能。DispatcherServlet
是个Servlet
(它继承自HttpServlet
基类),不过能做的比这更多。它与Spring IoC容器做到了无缝集成,这意味着,Spring提供的任何特性,在Spring MVC中你都可以使用。
DispatcherServlet
使用了特殊的bean来处理请求、渲染视图等,这些特定的bean是框架的一部分,依赖于这些特殊的bean来进行它的初始化。Spring MVC维护了一个默认的bean列表,如果你没有进行特别的配置,框架将会使用这些默认的bean。
DispatcherServlet
细分之后,可以整理出三个功能:
- 截获 HTTP 请求,并交由 Spring MVC 框架处理
- 处理调用关系
- 初始化并装配 Spring MVC 的各个组件
2,重要组件Bean列表
组件 Bean 类型 | 说明 |
---|---|
HandlerMapping | 处理器映射。它会根据某些规则将进入容器的请求映射到具体的处理器以及一系列前处理器和后处理器(即处理器拦截器)上。具体的规则视HandlerMapping 类的实现不同而有所不同。其最常用的一个实现支持你在控制器上添加注解,配置请求路径。当然,也存在其他的实现。 |
HandlerAdapter | 处理器适配器。拿到请求所对应的处理器后,适配器将负责去调用该处理器,这使得DispatcherServlet 无需关心具体的调用细节。比方说,要调用的是一个基于注解配置的控制器,那么调用前还需要从许多注解中解析出一些相应的信息。比如,调用注解实现的 Controller 需要解析其关联的注解. HandlerAdapter 的主要目的是为了屏蔽与 DispatcherServlet 之间的诸多细节。 |
HandlerExceptionResolver | 处理器异常解析器,它负责将捕获的异常映射到不同的视图上去,此外还支持更复杂的异常处理代码。 |
ViewResolver | 视图解析器,从处理器(Handler)返回字符类型的逻辑视图名称解析出实际的 View 对象,该对象将渲染后的内容输出到HTTP 响应中。 |
MultipartResolver | 解析multi-part的传输请求,比如支持通过HTML表单进行的文件上传等。 |
3,主要组件
3.1 处理器映射(HandlerMapping)
职责: HandlerMapping
的作用是根据当前请求的找到对应的 Handler
,并将 Handler
(执行程序)与 HandlerInterceptor
(拦截器)封装到 HandlerExecutionChain
对象(处理程序执行链,由处理程序对象和处理程序拦截器组成)中并返回。
参与时机: 在请求到达 DispatcherServlet#doDispatch
的时候,会根据当前请求来确定处理程序,详细流程如下:
1,首先调用getHandler
方法,从容器中取出所有 HandlerMapping
接口实例并遍历,让 HandlerMapping
接口的实例根据自己实现类的方式去尝试查找 Handler
。
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
//...省略
// 查找给定请求的处理程序
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
2,在 HandlerMapping
接口的内部只有一个方法,从实现类 AbstractHandlerMapping
中的方法可以看出,会首先根据request获取到 handler
对象,然后通过request和 handler
来获取 HandlerExecutionChain
处理程序执行链。
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
//...省略
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
//...省略
// 获取 处理程序拦截器 HandlerInterceptor并进行组装,
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
return executionChain;
}
3,getHandlerExecutionChain
方法首先会将之前获取到 handler
装入 HandlerExecutionChain
中,然后通过遍历 处理程序拦截器 将符合条件的拦截器添加到 HandlerExecutionChain
处理程序执行链中并返回。
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
//获取拦截器
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}
4,最终获取到HandlerExecutionChain
对象后,交由 HandlerAdapter
(处理器适配器)进行下一步的处理。
3.2 处理器适配器(HandlerAdapter)
职责: Spring MVC的handler(Controller
、HttpRequestHandler
等)有多种实现方式,例如继承Controller
的,基于注解控制器方式的,HttpRequestHandler
方式的。由于实现方式不一样,调用方式就不确定了。 如果正常编写调用,就需要使用多个if else判断instance of,再添加实现方式,就需要修改源码,不符合对扩展开放,对修改关闭原则,所以Spring MVC提供了处理器适配器(HandlerAdapter
),屏蔽了各种handler的差异,以一种统一的方式进行处理。
在HandlerAdapter
中有三个方法,分别是supports
、handle
和getLastModified
,
public interface HandlerAdapter {
/**
* 判断是否支持传入的handler
*/
boolean supports(Object handler);
/**
* 使用给定的handler处理请求
*/
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
/**
* 返回上次修改时间,可以返回-1表示不支持
*/
long getLastModified(HttpServletRequest request, Object handler);
}
HandlerAdapter
是一个接口,有多种实现方式,不过在我们平时使用中,一般只会用到RequestMappingHandlerAdapter
这种实现,它应该是目前springMVC主要采用的实现,针对方法级的映射匹配处理。
RequestMappingHandlerAdapter
继承自AbstractHandlerMethodAdapter
抽象类,而AbstractHandlerMethodAdapter
是HandlerAdapter
接口的抽象实现。
继承关系:HandlerAdapter
-->AbstractHandlerMethodAdapter
-->RequestMappingHandlerAdapter
。
参与时机: 当一个请求被HandlerMapping
处理结束,来到处理器适配器进行处理时:
1,首先到AbstractHandlerMethodAdapter
中的handle
方法中,
2,然后在这个方法中调用抽象方法handleInternal
,
3,此时会调用实现类RequestMappingHandlerAdapter
中的handleInternal
方法实现,
4,在这个方法中最重要的就是invokeHandlerMethod
,它会调用我们自己编写Controller
中的RequestMapping
方法进行处理,以及其他配置的处理,得到处理结果后执行下一步。
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//...省略
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
} else {
mav = invokeHandlerMethod(request, response, handlerMethod);
}
//...省略
return mav;
}
3.3 视图解析器(ViewResolver)
职责: 在处理适配器处理完请求后,就会到视图解析器(ViewResolver)进行下一步的处理,Spring MVC中所有控制器的处理器方法都必须返回一个逻辑视图的名字,无论是显式返回(比如返回一个String
、View
或者对象)还是隐式返回(比如基于约定的返回)。Spring中的视图由一个视图名标识,并由视图解析器来渲染。
其余待补充
4,其他组件
4.1 拦截器(Interceptors)
职责: 可以配置处理器拦截器HandlerInterceptors
或web请求拦截器WebRequestInterceptors
等拦截器,并配置它们拦截所有进入容器的请求,或限定到符合特定模式的URL路径。这个没什么可以说的,大家也都熟,我们对Spring MVC进行功能扩展时经常会用到它。
参与时机: 在处理器映射进行Handle
装配的时候,会把拦截器给组装成列表,然后在 处理器适配器 进行处理的时候,会按照设置对拦截器进行执行,请求到来拦截器的执行在下述REST相关组件
之前,返回处理在下述REST相关组件
之后。
使用方法: 见 对SpringMVC进行扩展 中的介绍
4.2 处理器异常解析器(HandlerExceptionResolver)
职责: 对出现异常的请求进行处理,这个咱们公司已经使用了统一异常拦截方式( @controlleradvice
+@ExceptionHandler
),对这个已经不再使用,没有介绍的必要。
参与时机: 当请求出现异常时。
使用方法: 略
4.3 具体处理请求控制器(Controller/Handler)
职责: 自己编写的controller就是处理请求的处理器,这个不需要介绍,大家天天用。
参与时机: 在处理器适配器进行时,会匹配到我们自己编写的请求处理器,进行处理。
使用方法: 自己编写,使用@Controller
和@xxxMapping
等注解进行声明。
4.4 文件上传(MultipartResolver)
待补充
5,REST相关组件
5.1 处理方法参数解析器(HandlerMethodArgumentResolver)
职责: 用于 HTTP 请求中解析 HandlerMethod
参数内容,处理成Handler
可用的参数数据,
参与时机: 在请求到来,进行到要对进行参数处理的时候,就会在方法参数解析器列表查找匹配的处理器,对参数进行处理。
使用方法: 见 对SpringMVC进行扩展 中的介绍
5.2 处理方法返回值解析器(HandlerMethodReturnValueHandler)
职责: 用于 HandlerMethod
返回值解析为 HTTP 响应内容
参与时机: 当方法处理完毕后,得到返回值之后,就会在方法返回值解析器列表中查找匹配的处理器,针对返回值进行处理。
使用方法: 见 对SpringMVC进行扩展 中的介绍
5.3 HTTP消息转换器(HttpMessageConverter)
职责: HTTP 消息转换器,用于反序列化 HTTP 请求或序列化响应。这个组件是方法级别的,
参与时机: 在请求到来时和处理完毕进行返回的时候,可以数据进行转换和处理,对请求数据进行处理的时机在 处理方法参数解析器
之前,对返回值进行处理时在方法返回值解析器
之前。
使用方法: 见 对SpringMVC进行扩展 中的介绍
6,部分组件运行先后顺序
- 接收到一个请求
- 拦截器进行请求拦截
- HTTP消息转换器进行请求处理
- 方法参数解析器进行处理
- 用户编写的控制器Controller进行处理
- 方法返回值解析器进行返回值处理(待确认)
- HTTP消息转换器进行返回值处理(待确认)
- 拦截器进行返回值拦截处理(待确认)
- 返回请求结果
三、常用注解(了解即可)
请求和响应相关
注解 | 说明 | Spring Framework 版本 |
---|---|---|
@RestController | 等效于 @Controller + @ResponseBody | 4.0 + |
@RequestMapping | 应用控制器映射注解声明 | 2.5+ |
@xxxMapping | 等效于 @RequestMapping(method =RequestMethod.XXX) | 4.3+ |
@RequestParam | 获取请求参数 | 2.5+ |
@RequestHeader | 获取请求头 | 3.0+ |
@PathVariable | 获取请求路径变量 | 3.0+ |
@RequestBody | 获取完整请求主体内容 | 3.0+ |
@ResponseBody | 响应主体声明 | 2.5+ |
@PostConstruct | 会在依赖注入完成后被自动调用 | JavaEE注解 |