前言
上一篇文章写得是SpringMVC组件初始化,这篇文章我们来探讨一下SpringMVC的执行流程
SpringMVC执行流程
SpringMVC执行流程几乎是在面试时面试官对SpringMVC部分的必问之题,下面是SpirngMVC的执行原理图
这个是请求在SpringMVC的执行流程- DispatcherServlet:请求打过来由DispatcherServlet处理,它是 SpringMVC 中的前端控制器(中央控制器), 负责接收 Request 并将 Request 转发给对应的处理组件
- HandlerMapping:HandlerMapping 维护了 url 和 Controller(Handler)的 映 射关系 。 DispatcherServlet 接 收 请求, 然 后 从 HandlerMapping 查找处理请求的Controller(Handler),标注了@RequestMapping 的每个 method 都可以看成是一个 Handler,HandlerMapping 在请求到达之后, 它的作用便是找到请求相应的处理器 Handler 和 Interceptors。
- HandlerAdapter:SpringMVC通过HandlerAdapter对Handler进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。它的作用就是按照特定的规则去执行 Controller (Handler)
- Handler : Controller (Handler)负责处理请求,Controller 执行后并返回 ModelAndView 对象,其中包括了数据模型和逻辑视图,ModelAndView 是封装结果 视图的组件。Handler把结果返回给HandlerAdapter,HandlerAdapter把结果返回给DispatcherServlet前端控制器。
- ViewResolver:DispatcherServlet收到ModelAndView,调用视图解析器(ViewResolver)来解析HandlerAdapter传递的ModelAndView。Handler执行完成后返回的是逻辑视图,也就是视图名字,一个String ,还有一个Model就是数据模型,封装成ModelAndView。ViewResolver视图解析的作用就是根据视图名,把本地模板文件(比如:xx.jsp;xx.ftl)解析为View视图对象。View用来渲染视图,也就是负责把Handler返回的数据模型model,填充到模板(jsp;ftl)形成html格式的静态内容。
- 最后就是把生成的html通过response写给浏览器,浏览器进行html渲染展示。
核心类认识
开始之前先来认识几个对象,否则下面会晕菜
HandlerMethod :是的controller中方法的封装,其中包括在Controller的Bean对象以及Method方法对象
public class HandlerMethod { /** Logger that is available to subclasses */ protected final Log logger = LogFactory.getLog(HandlerMethod.class); private final Object bean; //controller对应的bean private final Method method; //方法对象 private final BeanFactory beanFactory; private final MethodParameter[] parameters; private final Method bridgedMethod;
MappedInterceptor :对拦截器的封装
public final class MappedInterceptor { private final String[] includePatterns; private final String[] excludePatterns; //排除 private final HandlerInterceptor interceptor; //拦截器
RequestMappingInfo : 对@Controller和@RequestMapping注解的类的方法进行解析,然后把解析的结果封装成RequestMappingInfo , 对象中包含了针对@RequestMapping注解的6个属性的匹配条件,DispaterServlet需要根据找到请求匹配的Handler就需要满足6个匹配条件。
- PatternsRequestCondition :模式请求路径过滤器 ,根据request请求路径进行匹配
- RequestMethodsRequestCondition : 请求方法过滤器,根据request请求方式进行匹配
- ParamsRequestCondition :请求参数过滤器,根据请求的参数进行匹配
- HeadersRequestCondition : 请求过滤器 ,根据请求头进行匹配
- ConsumesRequestCondition :根据 筛选出同请求Accpet匹配的媒体类型表达式列表
- ProducesRequestCondition :应答媒体类型过滤器,根据请求Content-Type媒体类型进行匹配
- RequestCondition (optional, custom request condition)
public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> { //根据url进行匹配 private final PatternsRequestCondition patternsCondition; //方法匹配条件 private final RequestMethodsRequestCondition methodsCondition; //请求参数过滤器,参数匹配条件 private final ParamsRequestCondition paramsCondition; //头字段过滤器,请求头匹配条件 private final HeadersRequestCondition headersCondition; //Consumes匹配条件 private final ConsumesRequestCondition consumesCondition; // Produces匹配条件 private final ProducesRequestCondition producesCondition;
DispatchServlet执行流程
DispatchServlet是一个Servlet,请求进来会执行 DispatcherServlet#doService 方法
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { ...省略... // Make framework objects available to handlers and view objects. //把容器对象设置到request request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); //把localeResolver设置给request request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); //把themeResolver设置给request 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)); } //设置flashMapManager request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); try { //执行请求分发 doDispatch(request, response); } finally { if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { return; } // Restore the original attribute snapshot, in case of an include. if (attributesSnapshot != null) { restoreAttributesAfterInclude(request, attributesSnapshot); } } }
DispatcherServlet#doService调用了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 { //1.检查是否是Multipart文件上传 processedRequest = checkMultipart(request); multipartRequestParsed = processedRequest != request; // Determine handler for the current request. //2.遍历所有 handlerMappings 找到当前请求对应的handler, //比如:RequestMappingHandlerMapping 中维护了一个LinkedHashMap类型的handlerMethods, //是对HandlerMethod的存储。底层根据URL从handlerMethods匹配一个HandlerMethod, //然后把HandlerMethod封装到一个HandlerExecutionChain中 //HandlerMethod是对controller方法method的封装, //这里拿到的是HandlerExecutionChain handler执行链,其中封装了Handler和inteceptor mappedHandler = getHandler(processedRequest, false); if (mappedHandler == null || mappedHandler.getHandler() == null) { //如果没找到会走404 noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. //3.从handlerAdapters中循环,找到支持handler的,处理请求适配器HandlerAdapter(如:RequestMappingHandlerAdapter) HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. //处理lastModified String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { String requestUri = urlPathHelper.getRequestUri(request); logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } //4.调用拦截器的preHandle if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } try { // Actually invoke the handler. //5.调用 HandlerAdapter 实际执行handler,返回ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); } finally { if (asyncManager.isConcurrentHandlingStarted()) { return; } } //6.处理默认的视图名,如果mv != null && !mv.hasView() //就会使用RequestToViewNameTranslator#getViewName解析一个默认的view applyDefaultViewName(request, mv); //7.调用拦截器的postHandle mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } //8.处理结果,内部会使用viewResolver.resolveViewName渲染视图得到View对象 //然后执行:View#render方法渲染 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 mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); return; } // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } }
这里对核心方法做一个解释
查找HandlerMethod
getHandler 方法:该方法是遍历所有 handlerMappings ,找到合适的HandlerMapping,然后通过HandlerMapping#getHandler查找当前请求对应的HandlerMethod。(HandlerMethod是对controller中方法的封装),这里拿到的是HandlerExecutionChain 执行链而不是HandlerMethod,HandlerExecutionChain中封装了HandlerMethod和inteceptor拦截器;见:org.springframework.web.servlet.DispatcherServlet#getHandler(javax.servlet.http.HttpServletRequest)
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() + "'"); } //使用HandlerMapping 获取处理请求的Handler,封装到HandlerExecutionChain执行链对象中 //HandlerExecutionChain包括了HandlerMethod和interceptor拦截器 HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; } public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { //找到Handler Object handler = getHandlerInternal(request); if (handler == null) { handler = getDefaultHandler(); } if (handler == null) { return null; } // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } //把handler封装成HandlerExecutionChain ,其中还包括了拦截器的封装 return getHandlerExecutionChain(handler, request); } protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { //创建一个Handler执行链对象 HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain) ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler); //添加拦截器到HandlerExecutionChain chain.addInterceptors(getAdaptedInterceptors()); String lookupPath = urlPathHelper.getLookupPathForRequest(request); for (MappedInterceptor mappedInterceptor : mappedInterceptors) { if (mappedInterceptor.matches(lookupPath, pathMatcher)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } return chain; }
getHandler方法最终会走到org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal ,该方法就是根据request查找一个HandlerMethod
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { //拿到请求的路径 String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); if (logger.isDebugEnabled()) { logger.debug("Looking up handler method for path " + lookupPath); } //根据请求路径,找到匹配的HandlerMethod HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); if (logger.isDebugEnabled()) { if (handlerMethod != null) { logger.debug("Returning handler method [" + handlerMethod + "]"); } else { logger.debug("Did not find handler method for [" + lookupPath + "]"); } } return (handlerMethod != null) ? handlerMethod.createWithResolvedBean() : null; }
这里在拿到请求的路径,根据请求路径,找到匹配的HandlerMethod,再往里面走
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { //matches是requestMppingInfo和HandlerMethod的匹配器集合 List<Match> matches = new ArrayList<Match>(); //根据请求的路径,从 this.urlMap中拿到RequestMappingInfo, //urlMap 是一个LinkedHashMap,存储了Url路径和RequestMappingInfo的映射关系 List<T> directPathMatches = this.urlMap.get(lookupPath); if (directPathMatches != null) { addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { // No choice but to go through all mappings //如果从urlMap中没有找到RequestMappingInfo,那么matches就是空的 //根据Request对象封装一个requestMppingInfo,然后handlerMethods的keySet中拿到对应的HandlerMethod,(会根据Request中的URL,请求方式,参数params,请求头headers,consumes,produces去匹配handlerMethods.keySet中的requestMppingInfo) //然后从handlerMethods根据requestMppingInfo拿到HandlerMethod //把requestMppingInfo和HandlerMethod封装成Match添加到matches中 addMatchingMappings(this.handlerMethods.keySet(), matches, request); } if (!matches.isEmpty()) { Comparator<Match> comparator = new MatchComparator(getMappingComparator(request)); Collections.sort(matches, comparator); if (logger.isTraceEnabled()) { logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches); } Match bestMatch = matches.get(0); if (matches.size() > 1) { Match secondBestMatch = matches.get(1); if (comparator.compare(bestMatch, secondBestMatch) == 0) { Method m1 = bestMatch.handlerMethod.getMethod(); Method m2 = secondBestMatch.handlerMethod.getMethod(); throw new IllegalStateException( "Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" + m1 + ", " + m2 + "}"); } } handleMatch(bestMatch.mapping, lookupPath, request); //从bestMatch拿到Handler return bestMatch.handlerMethod; } else { return handleNoMatch(handlerMethods.keySet(), lookupPath, request); } }
这里出现了两个集合,urlMap 和 handlerMethods ,urlMap 存储的是url和RequestMappingInfo的映射关系,handlerMethods 存储的是RequestMappingInfo和HandlerMethod的关系。
这里的代码比较复杂,先是从 urlMap中根据url拿到RequestMappingInfo集合然后,如果没获取到即:matches.isEmpty()就会调用addMatchingMappings去处理,有兴趣自己去断点一下,该方法的大致流程如下
- 根据request中的url,method,参数params,请求头headers,consumes,produces去创建一个requestMppingInfo
- 然后根据requestMppingInfo为key从handlerMethods拿到HandlerMethod封装成Match 对象添加到matches集合中
- 从Match 中拿到当前请求对应的HandlerMethod
那么这里的handlerMethods和urlMap 是哪儿来的?
以:RequestMappingHandlerMapping为例在其父类AbstractHandlerMethodMapping中维护了一个 Map<T, HandlerMethod> handlerMethods = new LinkedHashMap<T, HandlerMethod>()该集合中装的就是RequestMappingInfo和HandlerMethod的映射关系,RequestMappingInfo是的RequstMapping的封装,HandlerMethod是对Conroller中方法的封装。初始化流程如下
- AbstractHandlerMethodMapping它实现了InitializingBean接口,在RequestMappingHandlerMapping初始化的使用会触发AbstractHandlerMethodMapping#afterPropertiesSet方法
- 该方法中会调用AbstractHandlerMethodMapping#initHandlerMethods 初始化HandlerMethod,其实就是从容器中拿到所有标识了@Controller或者@RequestMapping注解的Bean,也就是controller,然后拿到其中的所有method封装成HandlerMethod对象,然后再拿到method上RequestMapping信息封装成RquestMappingInfo对象,再把RquestMappingInfo和HandlerMethod以前者为key,后置为value注册到handlerMethods集合中。
- 把Url路径和RequestMappingInfo的映射关系存储到AbstractHandlerMethodMapping类中的 MultiValueMap<String, T> urlMap = new LinkedMultiValueMap<String, T>()集合中
这个是在MappingHandlerMapping初始化的时候就把HandlerMethod封装好存储在了handlerMethods 集合中,当请求过来就根据Request去匹配一个RequestMappingInfo,然后再找到对应的HandlerMethod返回。
查找HandlerAdapter
查找HandlerAdapter在org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter中,
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"); }// org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supports public final boolean supports(Object handler) { return handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler); }
从handlerAdapters循环所有的HandlerAdapter,调用supports方法判断是否支持该Handler,如果支持就返回HandlerAdapter
调用拦截器的preHandle
代码在org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle方法中,在HandlerExecutionChain维护了一个HandlerInterceptor[] interceptors,存储了所有的拦截器。源码如下
public class HandlerExecutionChain { private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class); private final Object handler; //拦截器数组 private HandlerInterceptor[] interceptors; ...省略... boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { if (getInterceptors() != null) { for (int i = 0; i < getInterceptors().length; i++) { //拿到所有的拦截器,调用preHandle方法 HandlerInterceptor interceptor = getInterceptors()[i]; if (!interceptor.preHandle(request, response, this.handler)) { //如果拦截器返回false,即不放行就执行拦截器的afterCompletion方法 triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } } return true; }
调用HandlerAdatapter
找到HanlderMethod之后执行拦截器的preHandler方法,然后执行HandlerAdapter#handle,最终会调用RequestMappingHandlerAdapter#invokeHandleMethod
private ModelAndView invokeHandleMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { //把request和response包装到ServletWebRequest对象 ServletWebRequest webRequest = new ServletWebRequest(request, response); WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory); //ModelAndvView的容器对象,方法调用之后的view和model就会在该容器中 ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, requestMappingMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); asyncWebRequest.setTimeout(this.asyncRequestTimeout); final 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 + "]"); } requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result); } //调用HandlerMethod方法,底层回从HandlerMethod拿到Method,,然后使用反射进行调用 //把方法返回的viewName和model添加到mavContainer requestMappingMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } //获取ModelAndView,从mavContainer拿到viewName和model生成ModelAndView return getModelAndView(mavContainer, modelFactory, webRequest); }
invokeAndHandle底层调用该方法nvocableHandlerMethod#invokeForRequest
public final Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { //获取方法的参数 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { StringBuilder builder = new StringBuilder("Invoking ["); builder.append(this.getMethod().getName()).append("] method with arguments "); builder.append(Arrays.asList(args)); logger.trace(builder.toString()); } //传入参数,调用方法 Object returnValue = invoke(args); if (logger.isTraceEnabled()) { logger.trace("Method [" + this.getMethod().getName() + "] returned [" + returnValue + "]"); } return returnValue;}private Object invoke(Object... args) throws Exception { ReflectionUtils.makeAccessible(this.getBridgedMethod()); try { //反射调用方法 return getBridgedMethod().invoke(getBean(), args); } catch (IllegalArgumentException e) { String msg = getInvocationErrorMessage(e.getMessage(), args); throw new IllegalArgumentException(msg, e); } catch (InvocationTargetException e) { // Unwrap for HandlerExceptionResolvers ... Throwable targetException = e.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 { String msg = getInvocationErrorMessage("Failed to invoke controller method", args); throw new IllegalStateException(msg, targetException); } } }
viewResolver渲染视图
handler调用完成之后,代码来到DispatcherServlet#processDispatchResult负责处理结果
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 { //这里在调用handlerExceptionResolvers处理异常,会循环所有的handlerExceptionResolvers //然后根据exception生成一个ModelAndView 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) { //[重要]执行拦截器的interceptor.afterCompletion mappedHandler.triggerAfterCompletion(request, response, null); } }
代码来到org.springframework.web.servlet.DispatcherServlet#render,该方法负责渲染视图
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. //调用视图解析器,解析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() + "'"); } //【重要】调用view.render渲染视图 view.render(mv.getModelInternal(), request, response); } protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale, HttpServletRequest request) throws Exception { //调用视图解析器,根据viewName生产一个View for (ViewResolver viewResolver : this.viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; } } return null; }
resolveViewName方法循环所有的viewResolvers ,调用viewResolver.resolveViewName根据viewName解析一个View对象,底层调用AbstractCachingViewResolver#resolveViewName创建View,如下
protected AbstractUrlBasedView buildView(String viewName) throws Exception { AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass()); //前缀+viewName+后缀 view.setUrl(getPrefix() + viewName + getSuffix()); String contentType = getContentType(); if (contentType != null) { view.setContentType(contentType); } view.setRequestContextAttribute(getRequestContextAttribute()); view.setAttributesMap(getAttributesMap()); if (this.exposePathVariables != null) { view.setExposePathVariables(exposePathVariables); } return view; }
找到View之后,会调用View的render方法渲染视图,见:org.springframework.web.servlet.view.AbstractView#render
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); } //拿到model数据模型 Map<String, Object> mergedModel = createMergedOutputModel(model, request, response); prepareResponse(request, response); //渲染 renderMergedOutputModel(mergedModel, request, response); }
继续跟踪org.springframework.web.servlet.view.InternalResourceView#renderMergedOutputModel方法
protected void renderMergedOutputModel( Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { // Determine which request handle to expose to the RequestDispatcher. HttpServletRequest requestToExpose = getRequestToExpose(request); // Expose the model object as request attributes. //暴露model对象,把model中的数据设置为request的属性 exposeModelAsRequestAttributes(model, requestToExpose); // Expose helpers as request attributes, if any. exposeHelpers(requestToExpose); // Determine the path for the request dispatcher. //视图中的模板地址 如:WEB-INF/XX.JSP String dispatcherPath = prepareForRendering(requestToExpose, response); // Obtain a RequestDispatcher for the target resource (typically a JSP). //获取目标资源的RequestDispatcher(通常是JSP)。 RequestDispatcher rd = getRequestDispatcher(requestToExpose, dispatcherPath); if (rd == null) { throw new ServletException("Could not get RequestDispatcher for [" + getUrl() + "]: Check that the corresponding file exists within your web application archive!"); } // If already included or response already committed, perform include, else forward. //如果已included或已提交响应,请执行include,否则forward。 if (useInclude(requestToExpose, response)) { response.setContentType(getContentType()); if (logger.isDebugEnabled()) { logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'"); } rd.include(requestToExpose, response); } else { // Note: The forwarded resource is supposed to determine the content type itself. exposeForwardRequestAttributes(requestToExpose); if (logger.isDebugEnabled()) { logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'"); } //执行forward rd.forward(requestToExpose, response); } }
最后总结一个流程图
文章结束,如果对你有所帮助,请给个好评,如果对你有所帮助,请给个好评原文: https://blog.csdn.net/u014494148/article/details/122169592