SpringMVC的MVC即模型-视图-控制器,该框架围绕一个DispatcherServlet设计,DispatcherServlet会把请求分发给各个处理器进行处理。SpringMVC的工作流程如下图所示。
- 浏览器发起HTTP请求,发送给DS;
- DS寻找映射处理器HandlerMapping,这个对象是个Mapping对象,保存了URL->方法的映射关系,通过HandlerMapping找到对应的Controller;
- 调用Controller;
- Controller调用Service;
- Controller返回ModelAndView,ModelAndView包含了数据Model和视图名称;
- 通过试图处理器ViewResolver找到对应的视图View,并将数据Model交给视图View渲染;
- 返回HTTP响应。
精简后的源码如下:
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) {
doDispatch(request, response); // 在doservice方法中调用doDispath方法
}
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) {
// 根据当前请求在HandlerMapping中找到Controller,HandlerMapping是个接口,一般在其实现类RequestMappingHandlerMapping中调用方法,返回的controller被包装在HandlerExecutionChain类中,HandlerExecutionChain中主要包含Controller和Interceptor拦截器
HandlerExecutionChain mappedHandler = getHandler(processedRequest);
// 如果没找到,返回404
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 根据当前controller找到HandlerAdapter,一般是RequestMappingHandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 执行前置拦截器
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 调用handle方法返回ModelAndView
ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 调用后置拦截器
mappedHandler.applyPostHandle(processedRequest, response, mv);
processDispatchResult(processedRequest, response, mappedHandler, mv);
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
// 通过ViewResolver返回View
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
}
}
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale =
(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
response.setLocale(locale);
View view;
String viewName = mv.getViewName();
if (viewName != null) {
// 通过viewName解析出View
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
}
// 视图渲染
view.render(mv.getModelInternal(), request, response);
}