赞
踩
在RequestMappingHandlerAdapter#invokeHandlerMethod()方法中
@Nullable protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { //将Request和Response进行封装 ServletWebRequest webRequest = new ServletWebRequest(request, response); try { //WebDataBinderFactory --> 工厂类,为目标对象创建一个WebDataBinder实例 // 1.WebDataBinder继承了DataBinder类,为web请求提供了参数绑定服务 WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); // 获取ModelFactory: // 2.ModelFactory可以协助控制器在调用方法之前初始化模型,并在调用之后更新模型 ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); // 创建InvocableHandlerMethod实例,以及各个组件的配置; // 后面通过调用invokeAndHandle()方法执行处理器 ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); // 4.尝试绑定参数、返回值解析器 if (this.argumentResolvers != null) { invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); } if (this.returnValueHandlers != null) { invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); } 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); // 6.异步请求相关 AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); asyncWebRequest.setTimeout(this.asyncRequestTimeout); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.setTaskExecutor(this.taskExecutor); asyncManager.setAsyncWebRequest(asyncWebRequest); asyncManager.registerCallableInterceptors(this.callableInterceptors); asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors); if (asyncManager.hasConcurrentResult()) { Object result = asyncManager.getConcurrentResult(); mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0]; asyncManager.clearConcurrentResult(); if (logger.isDebugEnabled()) { logger.debug("Found concurrent result value [" + result + "]"); } invocableMethod = invocableMethod.wrapConcurrentResult(result); } // 7.调用Controller中的具体方法并处理返回值 执行处理器 invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } // 8.返回ModelAndView对象 return getModelAndView(mavContainer, modelFactory, webRequest); } finally { // 完成请求后续处理,并将当前请求置为未激活 webRequest.requestCompleted(); } }
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 1.调用Controller中的具体方法 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); // 2.设置返回状态码 setResponseStatus(webRequest); // 3.当前请求无返回值或者返回值中包含错误,则将请求完成标识设置为true并返回 if (returnValue == null) { if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) { mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(getResponseStatusReason())) { mavContainer.setRequestHandled(true); return; } // 4.当前请求有返回值且无错误信息,则将请求完成标识设置为false,并继续处理当前请求 mavContainer.setRequestHandled(false); Assert.state(this.returnValueHandlers != null, "No return value handlers"); try { // 选取合适的HandlerMethodReturnValueHandler,并处理返回值 this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex); } throw ex; } }
@Override
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);
}
@Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { // 当前请求返回值为null,无需处理,并且要将当前请求标记已处理 if (returnValue == null) { mavContainer.setRequestHandled(true); return; } // 处理引用视图 ModelAndView mav = (ModelAndView) returnValue; if (mav.isReference()) { String viewName = mav.getViewName(); mavContainer.setViewName(viewName); if (viewName != null && isRedirectViewName(viewName)) { mavContainer.setRedirectModelScenario(true); } } // 处理普通视图(即我们已经制定了具体的View视图,而无需通过视图解析器再次解析) else { View view = mav.getView(); mavContainer.setView(view); if (view instanceof SmartView && ((SmartView) view).isRedirectView()) { mavContainer.setRedirectModelScenario(true); } } // 设置返回状态 mavContainer.setStatus(mav.getStatus()); //设置数据Model mavContainer.addAllAttributes(mav.getModel()); }
从ModelAndViewContainer容器中获取ModeAndView实例
@Nullable private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { // 1.更新模型 modelFactory.updateModel(webRequest, mavContainer); if (mavContainer.isRequestHandled()) { return null; } // 2.获取ModelMap并创建ModelAndView ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus()); // 3.处理引用类型视图和转发类型视图 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
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); } } // 尝试解析视图和模型; // wasCleared:判断当前模型和视图是否已经被标识为清空,且当前视图和模型是否同时为空 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()) { return; } // 处理注册的后置完成拦截器 if (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, null); } }
processDispatchResult() 方法
@Nullable protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) throws Exception { ModelAndView exMv = null; if (this.handlerExceptionResolvers != null) { //遍历所有的异常解析器, 尝试对异常进行解析, 如果解析成功,跳出循焕 for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) { exMv = handlerExceptionResolver.resolveException(request, response, handler, ex); if (exMv != null) { break; } } } if (exMv != null) { if (exMv.isEmpty()) { request.setAttribute(EXCEPTION_ATTRIBUTE, ex); return null; } //对于简单的错误模型,我们可能仍需要视图名称转换 if (!exMv.hasView()) { String defaultViewName = getDefaultViewName(request); if (defaultViewName != null) { exMv.setViewName(defaultViewName); } } if (logger.isDebugEnabled()) { logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex); } //设置错误请求的相关属性 WebUtils.exposeErrorRequestAttributes(request, ex, getServletName()); return exMv; } throw ex; }
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) { 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() + "'"); } } // 获取到视图名,再次判断当前ModelAndView对象中是否包含真正的View对象, // 因为接下来需要调用View对象的render方法 else { 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 { // 设置返回状态码 if (mv.getStatus() != null) { response.setStatus(mv.getStatus().value()); } // 调用View对象的render方法完成视图解析 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; } }
ModelAndView视图解析可以分为两个重要步骤:
public interface ViewResolver {
// 通过逻辑视图名和用户地区信息生成View对象
@Nullable
View resolveViewName(String viewName, Locale locale) throws Exception;
}
public interface View { String RESPONSE_STATUS_ATTRIBUTE = View.class.getName() + ".responseStatus"; String PATH_VARIABLES = View.class.getName() + ".pathVariables"; String SELECTED_CONTENT_TYPE = View.class.getName() + ".selectedContentType"; //获取返回值的contentType @Nullable default String getContentType() { return null; } //通过用户提供的模型数据与视图信息渲染视图 void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception; }
//根据视图名称创建View实例 @Nullable 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; }
public View resolveViewName(String viewName, Locale locale) throws Exception { //判断缓存是否可用 if (!isCache()) { //如果缓存不可用, 则直接创建视图 return createView(viewName, locale); } else { //如果缓存可用, 则先尝试从缓存中获取 //生成缓存Key Object cacheKey = getCacheKey(viewName, locale); //尝试从缓存中获取视图 View view = this.viewAccessCache.get(cacheKey); if (view == null) { //如果从缓存中获取视图失败, 则尝试从viewCreationCache缓存中获取 synchronized (this.viewCreationCache) { //让子类创建View对象, 留给子类扩展[扩展开放,修改关闭原则] view = this.viewCreationCache.get(cacheKey); if (view == null) { // 这里cacheUnresolved指的是是否缓存默认的空视图,UNRESOLVED_VIEW是 // 一个没有任何内容的View view = createView(viewName, locale); if (view == null && this.cacheUnresolved) { view = UNRESOLVED_VIEW; } if (view != null) { //将创建的view视图加入缓存 this.viewAccessCache.put(cacheKey, view); this.viewCreationCache.put(cacheKey, view); if (logger.isTraceEnabled()) { logger.trace("Cached view [" + cacheKey + "]"); } } } } } return (view != UNRESOLVED_VIEW ? view : null); } }
@Override protected View createView(String viewName, Locale locale) throws Exception { if (!canHandle(viewName, locale)) { return null; } // 检查特殊的"redirect:"前缀 REDIRECT_URL_PREFIX = "redirect:" // 如果是以"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:"前缀 FORWARD_URL_PREFIX = "forward:" // 如果是以"forward:" 开头, 说明该视图是请求转发 if (viewName.startsWith(FORWARD_URL_PREFIX)) { String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length()); return new InternalResourceView(forwardUrl); } //如果是普通视图, 创建该视图视图 return super.createView(viewName, locale); }
@Override
protected View loadView(String viewName, Locale locale) throws Exception {
// 使用逻辑视图名按照指定规则生成View对象
AbstractUrlBasedView view = buildView(viewName);
// 应用声明周期函数,也就是调用View对象的初始化函数和Spring用于切入bean创建的
View result = applyLifecycleMethods(viewName, view);
// 检查view的准确性,这里默认始终返回true
return (view.checkResource(locale) ? result : null);
}
protected AbstractUrlBasedView buildView(String viewName) throws Exception { //对于InternalResourceViewResolver而言,其返回的View对象的具体类型是InternalResourceView Class<?> viewClass = getViewClass(); Assert.state(viewClass != null, "No view class"); // 使用反射生成InternalResourceView对象实例 AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(viewClass); //根据前缀和后缀拼接视图路径信息 view.setUrl(getPrefix() + viewName + getSuffix()); // 设置View的contentType属性 String contentType = getContentType(); if (contentType != null) { view.setContentType(contentType); } // 设置contextAttribute和attributeMap等属性 view.setRequestContextAttribute(getRequestContextAttribute()); view.setAttributesMap(getAttributesMap()); // pathVariables表示request请求url中的属性,这里主要是设置是否将这些属性暴露到视图中 Boolean exposePathVariables = getExposePathVariables(); if (exposePathVariables != null) { view.setExposePathVariables(exposePathVariables); } // 这里设置的是是否将Spring的bean暴露在视图中,以供给前端调用 Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes(); if (exposeContextBeansAsAttributes != null) { view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes); } // 设置需要暴露给前端页面的bean名称 String[] exposedContextBeanNames = getExposedContextBeanNames(); if (exposedContextBeanNames != null) { view.setExposedContextBeanNames(exposedContextBeanNames); } return view; }
protected View applyLifecycleMethods(String viewName, AbstractUrlBasedView view) {
ApplicationContext context = getApplicationContext();
if (context != null) {
// 对生成的View对象应用初始化方法,主要包括InitializingBean.afterProperties()和一些
// Processor,Aware方法
Object initialized = context.getAutowireCapableBeanFactory().initializeBean(view, viewName);
if (initialized instanceof View) {
return (View) initialized;
}
}
return view;
}
@Override
public void render(@Nullable 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对象,以供给后面对视图的渲染使用
Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
// 判断当前View对象的类型是否为文件下载类型,如果是文件下载类型,则设置response的
prepareResponse(request, response);
// 开始view视图渲染以及数据输出整理
renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}
@Override protected void renderMergedOutputModel( Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { // 将Model中的键值对数据全部写进RequestScope中 exposeModelAsRequestAttributes(model, request); // 提供的一个hook方法,默认是空实现,用于用户进行request属性的自定义使用 exposeHelpers(request); //确定请求分配器的路径 String dispatcherPath = prepareForRendering(request, response); // 获取可应用于 forward/include 的RequestDispatcher 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请求,如果是,则调用RequestDispatcher.include()方法进行文件引入 if (useInclude(request, response)) { response.setContentType(getContentType()); if (logger.isDebugEnabled()) { logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'"); } rd.include(request, response); } // 请求转发 //使用forward跳转则后面的response输出则不会执行,而用include来跳转, //则include的servlet执行完后,再返回到原来的servlet执行response的输出(如果有) else { if (logger.isDebugEnabled()) { logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'"); } //如果当前不是include()请求,则直接使用forward请求将当前请求转发到目标文件路径中,从而渲染该视图 rd.forward(request, response); } }
视图解析分析完成
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。