1.DispatcherServlet作用说明
DispatcherServlet提供Spring Web MVC的集中访问点,而且负责职责的分派,而且与Spring IoC容器无缝集成,从而可以获得Spring的所有好处。DispatcherServlet主要用作职责调度工作,本身主要用于控制流程,主要职责如下:
1、文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;
2、通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个HandlerInterceptor拦截器);
3、通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器);
4、通过ViewResolver解析逻辑视图名到具体视图实现;
5、本地化解析;
6、渲染具体的视图等;
7、如果执行过程中遇到异常将交给HandlerExceptionResolver来解析。
2.具体实现说明
看着上面的总结肯定知道了大体上的处理过程,但是对于实际的逻辑实现肯定是一头雾水,DispatcherServlet的主要处理是在doDispatch()方法中实现的。看看具体的代码实现:
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); // Determine handler for the current request. mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(request, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, 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); } } } }
2.1请求类型处理
首先看代码:processedRequest = checkMultipart(request);就是为了处理文件类型的请求,如果请求类型是multipart将其转化通过MultipartResolver进行文件上传解析;如果不是就返回原来的请求。
protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException { if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) { if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) { logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " + "this typically results from an additional MultipartFilter in web.xml"); } else if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) instanceof MultipartException) { logger.debug("Multipart resolution failed for current request before - " + "skipping re-resolution for undisturbed error rendering"); } else { return this.multipartResolver.resolveMultipart(request); } } // If not returned before: return original request. return request; }
首先判断是不是MultipartHttpServletRequest请求,如果是就不需要再处理了,如果是这继续判断是否含有文件解析失败异常,如果没有最后才会调用MultipartResolver接口实现类的resolveMultipart()方法来具体处理这个请求并且最后返回MultipartHttpServletRequest。当然了如果不是一个文件类型的请求就会直接的返回原始请求。
2.2 根据请求获取能够处理该请求的HandlerExecutionChain
doDispatch()方法中的mappedHandler = getHandler(processedRequest);完成了HandlerExecutionChain(处理器运行链,由处理器和处理器拦截器组成)的寻找定位工作。看下如何具体获取HandlerExecutionChain的过程:
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { for (HandlerMapping hm : this.handlerMappings) { if (logger.isTraceEnabled()) { logger.trace( "Testing handler map [" + hm + "] in DispatcherServlet with name ‘" + getServletName() + "‘"); } HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; }
这个过程就和SpringMVC处理化的过程有关了,SpringMVC初始化中通过initHandlerMappings(ApplicationContext context)方法初始化了List<HandlerMapping> handlerMappings;也就是通过将所有配置的请求映射放到了这个handlerMappings。这个方法的处理过程简单就是循环遍历这个handlerMappings,如果找到了就返回具体的HandlerMapping 中的HandlerExecutionChain,否则就返回null.如果返回的处理器为空,说明没有能够处理这个请求的 HandlerMapping,那么就会调用noHandlerFound(processedRequest, response)进行处理,看下noHandlerFound(processedRequest, response)具体的工作。
protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception { if (pageNotFoundLogger.isWarnEnabled()) { pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" + getRequestUri(request) + "] in DispatcherServlet with name ‘" + getServletName() + "‘"); } if (this.throwExceptionIfNoHandlerFound) { ServletServerHttpRequest sshr = new ServletServerHttpRequest(request); throw new NoHandlerFoundException( sshr.getMethod().name(), sshr.getServletRequest().getRequestURI(), sshr.getHeaders()); } else { response.sendError(HttpServletResponse.SC_NOT_FOUND); } }
设置HTTP响应状态,并且抛出异常。
2.3 获取请求对应的处理器适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());决定了获取请求对应的处理器适配器。看下具体的实现:
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { for (HandlerAdapter ha : this.handlerAdapters) { if (logger.isTraceEnabled()) { logger.trace("Testing handler adapter [" + ha + "]"); } if (ha.supports(handler)) { return ha; } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
和获取请求的HandlerExecutionChain对象一样,遍历初始化就完成的handlerAdapters,有返回没有则抛出异常。
2.4 GET 和 HEAD请求处理
对于请求方式是GET或者HEAD的,会判断是否发生改变,如果没有改变就直接返回,否则就继续下去
2.5 调用具体的HandlerAdapter处理请求
方法ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;是使用给定的处理器来处理这个请求,并且返回一个ModelAndView 。以SimpleServletHandlerAdapter为例,其实是调用一个Servlet的Service方法来进行相应的业务逻辑的处理的。
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ((Servlet) handler).service(request, response); return null; }
2.6返回视图的再处理
对上面处理后的视图或者异常转化成一个ModelAndView对象:
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception { boolean errorView = false; if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handler, exception); errorView = (mv != null); } } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isDebugEnabled()) { logger.debug("Null ModelAndView returned to DispatcherServlet with name ‘" + getServletName() + "‘: assuming HandlerAdapter completed request handling"); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } if (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, null); } }
如果有异常则将异常转化成ModelAndView,如果视图不为空,则调用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.resolveLocale(request); response.setLocale(locale); View view; if (mv.isReference()) { // We need to resolve the view name. view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request); if (view == null) { throw new ServletException("Could not resolve view with name ‘" + mv.getViewName() + "‘ in servlet with name ‘" + getServletName() + "‘"); } } else { // No need to lookup: the ModelAndView object contains the actual View object. view = mv.getView(); if (view == null) { throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " + "View object in servlet with name ‘" + getServletName() + "‘"); } } // Delegate to the View object for rendering. if (logger.isDebugEnabled()) { logger.debug("Rendering view [" + view + "] in DispatcherServlet with name ‘" + getServletName() + "‘"); } try { view.render(mv.getModelInternal(), request, response); } catch (Exception ex) { if (logger.isDebugEnabled()) { logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name ‘" + getServletName() + "‘", ex); } throw ex; } }
首先获取请求的本地化处理并且将其设置到response中,如果指定了视图名字那么DispatcherServlet就会调用相应的视图解析器来进行解析,返回View对象
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception { for (ViewResolver viewResolver : this.viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; } } return null; }
如果ModelAndView 没有视图引用说明,它已经含有了一个真实的View对象直接过去即可。如果获取的View对象为空则需要爆出异常。最后也是最重要的就是调用View对象的render方法( view.render(mv.getModelInternal(), request, response))进行视图的渲染了。看具体实现是在View的实现抽象类中AbstractView中。
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isTraceEnabled()) { logger.trace("Rendering view with name ‘" + this.beanName + "‘ with model " + model + " and static attributes " + this.staticAttributes); } Map<String, Object> mergedModel = createMergedOutputModel(model, request, response); prepareResponse(request, response); renderMergedOutputModel(mergedModel, getRequestToExpose(request), response); }
简单的说就是获取数据并且填充,打完收工。
3.总结
上面便是按照DispatcherServlet从接受到一个请求到请求完全处理完成所经历的一个过程,很是清晰明确。设计也很简单。从设计到实现,可以察觉设计模式的几大原则和具体的设计都有涉及,从中也学到了很多东西,接着学习,加油。