原创

Spring MVC

Spring MVC流程

  1. 用户发起请求到DispathcherServlet(中央调度器)
  2. 中央调度器接收倒请求后调用handlerMapping映射器,handlerMapping通过url获取HandlerExecutionChain对象,里面包含了handler(handdlerMethod Controller的方法)、handlerInterceptor;
  3. 中央调度器调用handlerAdapter,通过适配器模式获取适应的处理器,执行不同的handler(执行Controller的方法);
  4. handler执行完给handlerAdapter返回 ModelAndView;
  5. handlerAdapter将ModelAndView返回给 中央调度器  ;
  6. 中央调度器  将ModelAndView给ViewResloer进行视图解析;
  7. ViewResloer将解析后的View返回给中央调度器;
  8. 中央调度器将model填充到View中进行视图渲染,然后返回给用户;
  • DispatcherServlet:中央调度器, 接受请求,响应结果,作为其他组件的转发者,降低其他组件的耦合度;
  • HandlerMapping:处理器映射器, 根据url去获取handler(可以理解为通过url获取指定Controller的Method);
  • HandlerAdapter:处理器 ,基础的有RequestMappingHandlerAdapter(执行@RequestMapping的修饰的方法),HandlerFunctionAdapter(用于处理实现HandlerFunction接口的实现类),HttpRequestHandlerAdapter(用于处理实现HttpRequestHandler接口的实现类,大多数用于静态资源),SimpleControllerAdapter(用于处理实现HttpRequestHandler接口的实现类);
  • ViewResolver:视图解析器 ,根据逻辑视图名解析成真正的视图;

组件

  • handlerMapping:根据url找到响应的处理器,常用的是找到Method
  • handlerAdapter:找到handler适合的类型,并执行handler
  • handlerExceptionResolver:处理handler产生的异常
  • requestToViewNameTranslator:当ModelAndView对象不为空且里面的属性为空才会生效,默认返回请求路径的viewName
  • ViewResolver:视图解析器,将viewName解析为真正的view视图
  • LocaleResolver:解析出用户的区域
  • theseResolver:主题,一个主题对应一个properties文件,里面包含图片、颜色、css样式等;
  • multipartResolver:将文件包装恒Multipart
  • flashMapManager:用于重定向 Redirect 时的参数数据传递

源码解析

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;

WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

try {
ModelAndView mv = null;
Exception dispatchException = null;

try { //检查是否为文件 processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);

//获取到handler (获取到controller的方法 handlerMethod)
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}

//根据handler获取指定的HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// Process last-modified header, if supported by the handler. //是否直接用客户端的缓存 String method = request.getMethod();
boolean isGet = HttpMethod.GET.matches(method);
if (isGet || HttpMethod.HEAD.matches(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//在业务处理前调用拦截器的preHandle方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}

// Actually invoke the handler. //调用handler方法 (controller的方法) 如果是前后端分离 则此处会返回null mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//当ModelAndView对象存在但对象内的view属性不存在则默认返回请求路径的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);
} //将model数据填充到view里面,并执行拦截器的afterCompletion方法 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}


正文到此结束
该篇文章的评论功能已被站长关闭