至此,第二步已经全部结束,接下来要接触到HandlerAdapter。
第四步:
再次回到DispatcherServlet类的doDispatch方法,继续往下走,进到getHandlerAdapter方法中。
在DispatcherServlet类中维护了一个名为handlerAdapters的List集合,里面保存了所有的HandlerAdapter(处理映射器),Spring MVC默认给我们提供了三个:RequestMappingHandlerAdapter、HttpRequestHandlerAdapter和SimpleControllerHandlerAdapter。
我们先复习一下Spring MVC中构建Hanlder(处理器)的四种方法:
- 实现Controller接口(或继承AbstractHandler抽象类)。
- 实现HttpRequestHandler接口。
- 使用@RequestMapping注解。
- 继承HttpServlet(实现原始Servlet接口)。
Spring MVC中共有四个处理器适配器:
RequestMappingHandlerAdapter:适配通过@RequestMapping注解创建的Handler。
HttpRequestHandlerAdapter:适配通过实现HttpRequestHandler接口创建的Handler。
SimpleControllerHandlerAdapter:适配通过实现Controller接口(或继承AbstractHandler抽象类)创建的Handler。
SimpleServletHandlerAdapter(不再默认提供):适配通过继承HttpServlet(实现原始Servlet接口)创建的Handler。
// 决定使用哪个HandlerAdapter(处理映射器)来处理当前Handlerprotected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { // 遍历所有的 for (HandlerAdapter adapter : this.handlerAdapters) { if (adapter.supports(handler)) { return adapter; } } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");}
可以看出其实HandlerAdapter内部也只是通过Handler的类型来判断是否支持。
// RequestMappingHandlerAdapter类public final boolean supports(Object handler) { return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));}// SimpleControllerHandlerAdapter类public boolean supports(Object handler) { return (handler instanceof Controller);}// HttpRequestHandlerAdapter类public boolean supports(Object handler) { return (handler instanceof HttpRequestHandler);}// SimpleServletHandlerAdapter类public boolean supports(Object handler) { return (handler instanceof Servlet);}
再获得了指定的处理器适配器后,就该执行了该Handler了。
第五步:
适配器在执行Handler之前,会调用HandlerExecutionChain的applyPreHandle方法来触发前置拦截器。接着就是调用HandlerAdapter的handle方法来执行Handler,这里使用的是实现类RequestMappingHandlerAdapter类,而handle方法在其父抽象类AbstractHandlerMethodAdapter类中,最终会调用RequestMappingHandlerAdapter类的handleInternal方法。
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 { // 省略其他内容... // 执行前置拦截器 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 处理器映射器执行Handler方法 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); // 执行后置拦截器 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); } 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); } } }}
// AbstractHandlerMethodAdapter类public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler);}
// RequestMappingHandlerAdapter类protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav; checkRequest(request); // Execute invokeHandlerMethod in synchronized block if required. if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { mav = invokeHandlerMethod(request, response, handlerMethod); } } else { // No HttpSession available -> no mutex necessary mav = invokeHandlerMethod(request, response, handlerMethod); } } else { // 调用Handler方法,看名称带invkoe可知最终是使用反射调用 mav = invokeHandlerMethod(request, response, handlerMethod); } if (!response.containsHeader(HEADER_CACHE_CONTROL)) { if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers); } else { prepareResponse(response); } } return mav;}
然后我们需要进入invokeHandlerMethod方法,这个方法非常重要。WebDataBinderFactory对象是用来生产数据绑定器的,ModelFactory对象是用来生成Model模型的。
InvocableHandlerMethod抽象类是是对HandlerMethod接口的扩展,增加了调用能力(doInvoke方法)。这个能力在Spring MVC可是非常非常重要的,它能够在调用的时候,把方法入参的参数都封装进来(从HTTP request里,当然借助的必然是HandlerMethodArgumentResolver)。该类中有一个HandlerMethodArgumentResolverComposite对象存储了所有的HandlerMethodArgumentResolver,用于解析Handler方法的参数。
ServletInvocableHandlerMethod类是对InvocableHandlerMethod抽象类的扩展,它增加了返回值和响应状态码的处理,另外在ServletInvocableHandlerMethod有个内部类ConcurrentResultHandlerMethod继承于它,支持异常调用结果处理,Servlet容器下Controller在查找适配器时发起调用的最终就是ServletInvocableHandlerMethod。该类中有一个HandlerMethodReturnValueHandlerComposite对象存储了所有的HandlerMethodReturnValueHandler,用于解析Handler方法的返回值。
RequestMappingHandlerAdapter类默认提供了27个argumentResolver和15个returnValueResolver。
ModelAndViewContainer类可以把它定义为ModelAndView上下文的容器,它承担着整个请求过程中的数据传递工作,保存着Model和View的相关信息。
// RequestMappingHandlerAdapter类protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); try { WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); // 使用Handler方法构建一个ServletInvocableHandlerMethod对象,以便下面的方法调用 ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); // 为ServletInvocableHandlerMethod对象设置参数解析器和返回值解析器 if (this.argumentResolvers != null) { invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); } if (this.returnValueHandlers != null) { invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); } // 为ServletInvocableHandlerMethod对象设置数据绑定器工厂 invocableMethod.setDataBinderFactory(binderFactory); invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); // 创建一个模型视图容器 ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, invocableMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); // 省略其他内容... // 调用Handler方法 invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } // 通过ModelAndViewContainer构建一个ModelAndView对象 return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); }}
继续进入到invokeAndHandle方法内,结果发现第一行代码,又调用了一个叫invokeForRequest的方法。
// ServletInvocableHandlerMethod类public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 调用Handler方法并获得返回值 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); // 省略其他内容... try { // 使用返回值处理器来处理返回值 this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(formatErrorForReturnValue(returnValue), ex); } throw ex; }}
而当进入invokeForRequest方法后,发现它又调用了一个doInvoke方法。在doInvoke方法中,才是真正地通过反射调用了Handler方法,前面的方法可以说都是在做一些准备工作,例如获取方法的参数、创建可调用的方法对象、创建模型视图容器等。
// InvocableHandlerMethod类public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 获取Handler方法的所有参数值 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { logger.trace("Arguments: " + Arrays.toString(args)); } // 调用Handler方法 return doInvoke(args);}protected Object doInvoke(Object... args) throws Exception { // 获取到目标Handler方法的Method对象 Method method = getBridgedMethod(); ReflectionUtils.makeAccessible(method); try { if (KotlinDetector.isSuspendingFunction(method)) { return CoroutinesUtils.invokeSuspendingFunction(method, getBean(), args); } // 使用反射调用目标Handler方法 return method.invoke(getBean(), args); } catch (IllegalArgumentException ex) { assertTargetBean(method, getBean(), args); String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument"); throw new IllegalStateException(formatInvokeError(text, args), ex); } catch (InvocationTargetException ex) { // Unwrap for HandlerExceptionResolvers ... Throwable targetException = ex.getTargetException(); if (targetException instanceof RuntimeException) { throw (RuntimeException) targetException; } else if (targetException instanceof Error) { throw (Error) targetException; } else if (targetException instanceof Exception) { throw (Exception) targetException; } else { throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException); } }}
第六步:
看完Handler方法的调用,就该看如何处理方法返回值了。我们再回到invokeAndHandle方法中,下一个关键方法是handleReturnValue,它的作用是使用HandlerMethodReturnValueHandler(Handler方法 返回值处理器)来处理对应的返回值,这里使用的是适配器模式。
因为我这里返回的是一个字符串,所以应该是使用的ViewNameMethodReturnValueHandler返回值处理器。handleReturnValue方法并没有返回值,返回值(包括Model和View)将被存进ModelAndViewContainer容器中,以便后续使用。
// HandlerMethodReturnValueHandlerComposite类public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { // 选择一个合适的返回值处理器 HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType); if (handler == null) { throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName()); } // 使用指定的返回值处理器来处理返回值 handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);}// 选择一个合适的返回值处理器private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) { boolean isAsyncValue = isAsyncReturnValue(value, returnType); for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) { if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) { continue; } // 依次遍历返回值处理器并判断是否支持当前返回值类型 if (handler.supportsReturnType(returnType)) { return handler; } } return null;}// 使用指定的返回值处理器来处理返回值public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { if (returnValue instanceof CharSequence) { String viewName = returnValue.toString(); // 将视图名存入模型视图容器 mavContainer.setViewName(viewName); if (isRedirectViewName(viewName)) { mavContainer.setRedirectModelScenario(true); } } else if (returnValue != null) { // should not happen throw new UnsupportedOperationException("Unexpected return type: " + returnType.getParameterType().getName() + " in method: " + returnType.getMethod()); }}
第七步:
当HandlerMethodReturnValueHandler处理完Handler方法返回值后,就该将处理后的ModelAndView对象返回给DispatcherServlet类了。这一步就是调用RequestMappingHandlerAdapter类中invokeHandlerMethod方法的最后一行代码(即getModelAndView方法),获取ModelAndView对象。
在getModelAndView方法中,会对Model、View做最后的处理,从ModelAndViewContainer容器中取出Model和View来构建一个ModelAndView。
// RequestMappingHandlerAdapter类private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { modelFactory.updateModel(webRequest, mavContainer); if (mavContainer.isRequestHandled()) { return null; } ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus()); if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); } if (model instanceof RedirectAttributes) { Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); if (request != null) { RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } } return mav;}
第八步:
这一步是请求视图解析器解析ModelAndView对象。
去到DispatcherServlet类中的processDispatchResult方法,可以看到中间有一个render方法,该方法的主要作用就是渲染视图了,也基本是整个流程的收尾工作。
// DispatcherServlet类protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; // 处理器执行链 HandlerExecutionChain mappedHandler = null; // 是否为多部分类型请求 boolean multipartRequestParsed = false; // 管理异步请求的处理 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { // 省略其他内容... // 视图解析器解析视图 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()) { if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } }}private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable 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); } } // if (mv != null && !mv.wasCleared()) { render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isTraceEnabled()) { logger.trace("No view rendering, null ModelAndView returned."); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } if (mappedHandler != null) { // Exception (if any) is already handled.. mappedHandler.triggerAfterCompletion(request, response, null); }}
在该方法中,首先是通过地域解析器解析请求,在获取到地域信息后应用于响应中。然后获取视图名,传入resolveViewName方法进行解析。resolveViewName方法的作用就是将指定的视图名通过ViewResolver(视图解析器)解析为一个视图对象,DispatcherServlet类中维护了一个存有ViewResolver(视图解析器)的List集合,但Spring MVC默认不会提供视图解析器,这里是我们自己配置了一个InternalResourceViewResolver视图解析器,它继承于UrlBasedViewResolver类,可以用来处理URL路径的视图名或者拼接视图路径等,也可以通过"redirect:"和"forward:"来指明是重定向和请求转发。
看名字也能知道这是一个内部资源的视图解析器,注释中说了建议将视图放在/WEB-INF目录下,以便外界无法访问,只能通过Controller方法,JSP页面也常常使用该视图解析器。
下图是自己配置的视图解析器:
// DispatcherServlet类protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { // 决定地域信息,并应用于响应中,其实就是国际化处理 Locale locale = (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale()); response.setLocale(locale); View view; String viewName = mv.getViewName(); if (viewName != null) { // We need to resolve the view name. 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() + "'"); } } 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.isTraceEnabled()) { logger.trace("Rendering view [" + view + "] "); } 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; }}// 将指定的视图名解析为一个视图对象protected View resolveViewName(String viewName, @Nullable Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception { // 依次遍历每个视图解析器来尝试解析该视图名 if (this.viewResolvers != null) { for (ViewResolver viewResolver : this.viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; } } } return null;}
当选定一个视图解析器后,就执行其resolveViewName方法,该方法在InternalResourceViewResolver的间接父类AbstractCachingViewResolver抽象类中。createView方法来负责创建View对象,如果解析成功就会将其存入缓存viewAccessCache中,以后相同视图名就直接从缓存拿。
// AbstractCachingViewResolver抽象类public View resolveViewName(String viewName, Locale locale) throws Exception { if (!isCache()) { return createView(viewName, locale); } else { // 根据视图名获取缓存Key Object cacheKey = getCacheKey(viewName, locale); // 从缓存中获取对应的View对象(视图对象) View view = this.viewAccessCache.get(cacheKey); // 如果缓存中不存在才来创建 if (view == null) { synchronized (this.viewCreationCache) { view = this.viewCreationCache.get(cacheKey); if (view == null) { // 依靠子类来创建View对象(视图对象) view = createView(viewName, locale); if (view == null && this.cacheUnresolved) { view = UNRESOLVED_VIEW; } // 将创建的View对象存入缓存中 if (view != null && this.cacheFilter.filter(view, viewName, locale)) { this.viewAccessCache.put(cacheKey, view); this.viewCreationCache.put(cacheKey, view); } } } } else { if (logger.isTraceEnabled()) { logger.trace(formatKey(cacheKey) + "served from cache"); } } return (view != UNRESOLVED_VIEW ? view : null); }}
createView方法在其子类UrlBasedViewResolver类中,会根据不同的情况(重定向或请求转发)解析视图名。
// UrlBasedViewResolver类protected View createView(String viewName, Locale locale) throws Exception { // 判断当前视图解析器是否支持处理该视图名,如果不支持就返回一个null,这样后续就能交给下一个视图解析器再来尝试 if (!canHandle(viewName, locale)) { return null; } // 处理redirect:(重定向)的情况 if (viewName.startsWith(REDIRECT_URL_PREFIX)) { String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length()); RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible()); String[] hosts = getRedirectHosts(); if (hosts != null) { view.setHosts(hosts); } return applyLifecycleMethods(REDIRECT_URL_PREFIX, view); } // 处理forward:(请求转发)的情况 if (viewName.startsWith(FORWARD_URL_PREFIX)) { String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length()); InternalResourceView view = new InternalResourceView(forwardUrl); return applyLifecycleMethods(FORWARD_URL_PREFIX, view); } // Else fall back to superclass implementation: calling loadView. return super.createView(viewName, locale);}
// AbstractCachingViewResolver抽象类protected View createView(String viewName, Locale locale) throws Exception { return loadView(viewName, locale);}
在loadView方法中调用buildView方法来真正地创建视图对象,初始化了一个视图对象,然后使用指定的前缀和后缀加上视图名拼接一个URL。
// UrlBasedViewResolver类protected View loadView(String viewName, Locale locale) throws Exception { // 创建一个视图实例,这里是调用的InternalResourceViewResolver类中的方法 AbstractUrlBasedView view = buildView(viewName); View result = applyLifecycleMethods(viewName, view); return (view.checkResource(locale) ? result : null);}// InternalResourceViewResolver类protected AbstractUrlBasedView buildView(String viewName) throws Exception { // 这里又调用的父类UrlBasedViewResolver类中的方法 InternalResourceView view = (InternalResourceView) super.buildView(viewName); if (this.alwaysInclude != null) { view.setAlwaysInclude(this.alwaysInclude); } view.setPreventDispatchLoop(true); return view;}// UrlBasedViewResolver类protected AbstractUrlBasedView buildView(String viewName) throws Exception { // 初始化了一个InternalResourceView对象 AbstractUrlBasedView view = instantiateView(); // 为该视图设置URL,使用前缀+视图名+后缀的形式拼接 view.setUrl(getPrefix() + viewName + getSuffix()); view.setAttributesMap(getAttributesMap()); // 下面都是一些参数设置 String contentType = getContentType(); if (contentType != null) { view.setContentType(contentType); } String requestContextAttribute = getRequestContextAttribute(); if (requestContextAttribute != null) { view.setRequestContextAttribute(requestContextAttribute); } Boolean exposePathVariables = getExposePathVariables(); if (exposePathVariables != null) { view.setExposePathVariables(exposePathVariables); } Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes(); if (exposeContextBeansAsAttributes != null) { view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes); } String[] exposedContextBeanNames = getExposedContextBeanNames(); if (exposedContextBeanNames != null) { view.setExposedContextBeanNames(exposedContextBeanNames); } return view;}
第九步:
当buildView方法创建了一个View对象后,就一步步将该对象返回至DispatcherServelt类的render方法中。然后接下来进行最后一步,渲染视图。
// DispatcherServelt类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) { // View对象将返回至该方法中 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() + "'"); } } 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.isTraceEnabled()) { logger.trace("Rendering view [" + view + "] "); } 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; }}
第十步:
渲染视图还是在render方法中,不过是View对象中的render方法。最后一行的renderMergedOutputModel方法是真正执行渲染输出的方法,作用是渲染给定模型的内部资源。
通过Model对象为视图页面参数赋值,方式是将Model对象的参数依次设置为请求的attribute属性即可,因为在视图页面中会通过请求的attribute属性值来填充页面。
最后就是通过请求转发的方式将请求分发至对应页面。至此,Spring MVC对于请求的处理流程也就结束了!
// InternalResourceView类public void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception { // 省略其他内容... // 创建一个包含动态值和静态属性的组合输出映射, 动态值优先于静态属性 Map<String, Object> mergedModel = createMergedOutputModel(model, request, response); // 为渲染准备给定的响应 prepareResponse(request, response); renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);}// 渲染给定模型的内部资源protected void renderMergedOutputModel( Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { // 根据Model对象为视图页面设值,方式其实是通过为请求设置attribute参数的形式 exposeModelAsRequestAttributes(model, request); exposeHelpers(request); // 决定请求分派器的路径 String dispatcherPath = prepareForRendering(request, response); // 获取请求调度器 RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath); if (rd == null) { throw new ServletException("Could not get RequestDispatcher for [" + getUrl() + "]: Check that the corresponding file exists within your web application archive!"); } // include方式 if (useInclude(request, response)) { response.setContentType(getContentType()); if (logger.isDebugEnabled()) { logger.debug("Including [" + getUrl() + "]"); } rd.include(request, response); } // forward方式 else { if (logger.isDebugEnabled()) { logger.debug("Forwarding to [" + getUrl() + "]"); } // 根据URL路径进行请求转发 rd.forward(request, response); }}
原文转载:http://www.shaoqun.com/a/501287.html
tm商标:https://www.ikjzd.com/w/1069
3suisses:https://www.ikjzd.com/w/412
55海淘网:https://www.ikjzd.com/w/1723
至此,第二步已经全部结束,接下来要接触到HandlerAdapter。第四步:再次回到DispatcherServlet类的doDispatch方法,继续往下走,进到getHandlerAdapter方法中。在DispatcherServlet类中维护了一个名为handlerAdapters的List集合,里面保存了所有的HandlerAdapter(处理映射器),SpringMVC默认给我们提供
FEN:FEN
二类电商:二类电商
注册澳大利亚商标流程是怎样的?:注册澳大利亚商标流程是怎样的?
2020清明节清远好玩的地方?清远清明节适合去哪里玩?:2020清明节清远好玩的地方?清远清明节适合去哪里玩?
泰国玉佛寺门票要多少钱?:泰国玉佛寺门票要多少钱?
No comments:
Post a Comment