简介
SpringMVC的核心都是围绕着前端调度器-DispatcherServlet设计的,DispatcherServlet负责请求统一的调度,实际的工作交给相应的组件执行,各司其职,如下图:
SpringMVC请求流程
组件
DispatcherServlet
DispatcherServlet-前端调度器 负责拦截前端的请求 然后分发到各个处理器的方法中
HandlerMapping
处理器映射器负责通过请求的url 匹配 对应的执行器链。
HandlerAdapter
处理器适配器,负责执行处理器的具体方法,返回ModelAndView
ModelAndView
封装视图和数据
ViewReslover
解析ModelAndView 返回view
现在大部分项目都是前后端分离以JSON的方式进行数据交互,所以后面我们重点讲解DispatcherServlet、HandlerMapping、HandlerAdapter 这三个组件。
源码
DispatcherServlet 类图
dispatcherServlet 是Servlet的一个实现类吗,所以在请求进来时会进入到Servlet#Service方法,然后根据类图 一顿分析 可以得出 请求会进入到 DispatcherServlet#doService方法
doService
入口函数
:org.springframework.web.servlet#doService
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
logRequest(request);
.....省略代码
try {
// 调度逻辑找到了 继续跟
doDispatch(request, response);
}
.....省略代码
}
doDispatch
请求调度开始
:org.springframework.web.servlet#doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
..... 代码省略
HandlerExecutionChain mappedHandler = null;
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 检查是否为文件上传
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 根据reaquest 获取处理器链
// HandlerExecutionChain 对象 除了处理器handler 还包含拦截器等其他信息
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
// url没有对应的处理器 返回404 noHandlerFound 此处简单逻辑大家自己跟一下就好了
noHandlerFound(processedRequest, response);
return;
}
// 根据处理器获取到处理器适配器 为后面执行处理器准备
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
..... 代码省略
// 执行处理器链 中 拦截器的 preHandle 方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
// false直接返回
return;
}
// 处理器适配器执行具体的 处理器方法 返回 ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 设置viewName
applyDefaultViewName(processedRequest, mv);
// 执行处理器链 中 拦截器的 postHandle 方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 5.解析并渲染视图ModelAndView 正常执行拦截器afterCompletion 方法
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
// 异常执行拦截器afterCompletion 方法
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
// 异常执行拦截器afterCompletion 方法
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
..... 代码省略
}
processDispatchResult
渲染视图
:org.springframework.web.servlet#processDispatchResult
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
.....省略代码
if (mv != null && !mv.wasCleared()) {
// 渲染视图
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
.....省略代码
if (mappedHandler != null) {
// 执行拦截器 afterCompletion 方法
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
...
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// 此处会获取 视图解析器 viewResolvers 解析视图
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
...
try {
if (mv.getStatus() != null) {
response.setStatus(mv.getStatus().value());
}
// 渲染视图
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Error rendering view [" + view + "]", ex);
}
throw ex;
}
}
总结
本文将SpringMVC 整体的一个请求流程粗略的过了一遍,主要分下面几个步骤
- DispatcherServlet#doDispatch: 前端控制器开始调度请求流程.
- getHandler(processedRequest): 根据request 获取处理器 mappedHandler( HandlerExecutionChain 对象包括拦截器)
- getHandlerAdapter(mappedHandler.getHandler()): 根据处理器获取处理器适配器 ha
- mappedHandler.applyPreHandle(): 执行mappedHandler中拦截器的preHandle 方法
- ha.handle(): 处理器适配器 执行 处理器方法 返回视图
- mappedHandler.applyPostHandle() 执行mappedHandler中拦截器的postHandle 方法
- processDispatchResult():解析视图然后进行视图渲染 返回给客户端