上次明白了springmvc的初始化流程,现在来看看springmvc如何具体处理一个请求。
当一个请求到达服务器后,会交给servlet,如果是交给了DispatchServlet,那么就会调到
##doService方法
这个方法主要是往request里设置一些属性。方便之后handler和view获取。
// Make framework objects available to handlers and view objects. request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); try { //属性设置完后将request和response交给doDispatch doDispatch(request, response); } finally {
这里包含了完整的对这个请求的处理。
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); //通过getHandler决定用哪个handler,并返回一个HandlerExecutionChain对象。 //这个对象不仅包含handler,还提供了prehandler,posthandler,completionHandler拦截器的方法。 mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; }
///可以看到getHandler,实际上就是轮询哪个HandlerMapping能够处理这个request 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; }
///那this.handlerMapping是怎么初始化的呢?就是在所有的ApplicationContext,中找到实现了HandlerMapping的beans.如果我们没特别设置,会有一些默认的handlerMapping。 private void initHandlerMappings(ApplicationContext context){ this.handlerMappings = null; if (this.detectAllHandlerMappings) { // 在所有的ApplicationContext,中找到实现了HandlerMapping的beans. Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values()); // We keep HandlerMappings in sorted order. AnnotationAwareOrderComparator.sort(this.handlerMappings); } } else { try { HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerMapping later. } } // Ensure we have at least one HandlerMapping, by registering // a default HandlerMapping if no other mappings are found. if (this.handlerMappings == null) { this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); if (logger.isDebugEnabled()) { logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default"); } } }
ok,通过上面的代码,我们知道了handlerMapping是如何产生的,以及如何根据request找到对应的HandlerExecutionChain。
在执行前,spring将handler封装为一个HandlerAdapter。为什么要这么做呢?看看这个接口的定义
/** Interface that must be implemented for each handler type to handle a request. * This interface is used to allow the {@link DispatcherServlet} to be indefinitely * extensible. The {@code DispatcherServlet} accesses all installed handlers through * this interface, meaning that it does not contain code specific to any handler type. */ 大概是说为了扩展性,DispatchServlet不应该和任何具体的handler直接打交道,都通过HanlderAdapter来调用。
所以我们在doDispatch中看到了:
// Determine handler adapter for the current request. //挑选一个HandlerAdapter,所有handler的调用都通过adapter。 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
不过还有拦截器,如果设置了拦截器,那么我们应该先执行preHandler,在执行handler,再postHandler,最后在view渲染完后执行completionhandler。
//如果prehandler返回false,直接结束掉 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 通过adapter调用handler。 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); //执行posthandler mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } //处理渲染,之后执行completionhandler processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
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中会去根据viewname在viewresolver中找到对应的view进行render。 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) { //render完成了,执行completionhander。 mappedHandler.triggerAfterCompletion(request, response, null); } }
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()) { // 根据viewname找到对应的view 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 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; } }
ok支持整个request的流程就处理完了。
谢谢你请我吃糖果