SpringMVC之完整的处理流程

在这篇文章中,将要完整的跟踪一下SpringMVC的执行流程
在这里插入图片描述
我们会在浏览器里输入
http://localhost:8060/articles/67/comment?comment=sssss2ssssk1k1
最终的效果是
在这里插入图片描述
下面就开始走进源码:

protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//获取请求的类型
		String method = request.getMethod();
		if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) {
			processRequest(request, response);
		}
		else {
			super.service(request, response);
		}
	}

首先来到了FrameworkServlet的service方法,对于PATCH类型的直接调用processRequest方法,其他类型先调用父类的service方法,在这里我们的是get请求

protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String method = req.getMethod();

        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
            
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);
            
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
            
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
            
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);
            
        } else {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //

            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);
            
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }

这是HttpServlet的service方法,在这里面根据不同的请求类型进行了分发

protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

由于我们的是get请求,所以来到了FrameworkServlet的doGet方法里面,然后调用了processRequest方法

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//获取开始处理的时间
		long startTime = System.currentTimeMillis();
		Throwable failureCause = null;
		//保存原来的LocaleContext
		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
		//设置当前的LocaleContext
		LocaleContext localeContext = buildLocaleContext(request);
		//保存原来的RequestAttributes
		RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
		//设置当前的RequestAttributes
		ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
		//将当前的RequestAttributes和localeContext设置到LoaleContextHolder和RequestContextHolder中
		initContextHolders(request, localeContext, requestAttributes);

		try {
			//调用都Service方法
			doService(request, response);
		}
		catch (ServletException ex) {
			failureCause = ex;
			throw ex;
		}
		catch (IOException ex) {
			failureCause = ex;
			throw ex;
		}
		catch (Throwable ex) {
			failureCause = ex;
			throw new NestedServletException("Request processing failed", ex);
		}

		finally {
			//恢复原来的设置
			resetContextHolders(request, previousLocaleContext, previousAttributes);
			if (requestAttributes != null) {
				requestAttributes.requestCompleted();
			}

			if (logger.isDebugEnabled()) {
				if (failureCause != null) {
					this.logger.debug("Could not complete request", failureCause);
				}
				else {
					if (asyncManager.isConcurrentHandlingStarted()) {
						logger.debug("Leaving response open for concurrent processing");
					}
					else {
						this.logger.debug("Successfully completed request");
					}
				}
			}
			//发布一个事件
			publishRequestHandledEvent(request, response, startTime, failureCause);
		}
	}

可以看到这个方法首先将当前的RequestAttributes和localeContext设置到LoaleContextHolder和RequestContextHolder中,然后调用模板方法doService,这是在子类中执行,最后执行完后会发布ServletRequestHandledEvent消息

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		if (logger.isDebugEnabled()) {
			String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
			logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
					" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
		}

		// 根据是否是include类型来决定是否要保存当前request属性的快照信息
		Map<String, Object> attributesSnapshot = null;
		if (WebUtils.isIncludeRequest(request)) {
			attributesSnapshot = new HashMap<String, Object>();
			Enumeration<?> attrNames = request.getAttributeNames();
			while (attrNames.hasMoreElements()) {
				String attrName = (String) attrNames.nextElement();
				if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
					attributesSnapshot.put(attrName, request.getAttribute(attrName));
				}
			}
		}

		// 给request设置属性
		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 {
			//真正处理的方法
			doDispatch(request, response);
		}
		finally {
			if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
				// 如果是include类型的请求,需要恢复快照信息
				if (attributesSnapshot != null) {
					restoreAttributesAfterInclude(request, attributesSnapshot);
				}
			}
		}
	}

DispathcerServlet的doService方法将webApplicationContext、localeResolver、themeResolver、outputFlashMap和flashMapManager设置到了request属性中,然后将请求传递到了doDispatch方法中

processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);

首先会检查是否是上传文件的请求,如果是,需要转型

mappedHandler = getHandler(processedRequest);

解析来会根据request找到对应的Handler

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;
	}

在方法中会遍历容器中所以后的HandlerMapping,会和@RequestMapping里面配置的内容进行匹配,然后根据这个条件找到定义的处理器方法

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 = 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);
	}

首先需要获取我们请求的url,然后根据url和request里面的相关属性调用lookupHandlerMethod方法找到对应的HandlerMethod

List<Match> matches = new ArrayList<Match>();
		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...
			addMatchingMappings(this.handlerMethods.keySet(), matches, request);
		}

首先会尝试从urlMap里面直接查找匹配的条件,但是由于我们的url中articleId是动态的,所以获取不到,然后调用addMatchingMappings(this.handlerMethods.keySet(), matches, request),传入的参数是当前controller里面所有的匹配条件

private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
		for (T mapping : mappings) {
			T match = getMatchingMapping(mapping, request);
			if (match != null) {
				matches.add(new Match(match, this.handlerMethods.get(mapping)));
			}
		}
	}

将所有的匹配条件通过getMatchingMapping和我们的request进行比较,符合条件的会被放到matches中

protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
		return info.getMatchingCondition(request);
	}

然后调用匹配信息的getMatchingCondition进行判断

public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
		//开始会将所有需要比对的条件进行判断,如果符合的就会返回相应的值
		RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
		ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
		HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
		ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
		ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);

		if (methods == null || params == null || headers == null || consumes == null || produces == null) {
			return null;
		}
		//匹配url
		PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
		if (patterns == null) {
			return null;
		}

		RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
		if (custom == null) {
			return null;
		}

		return new RequestMappingInfo(this.name, patterns,
				methods, params, headers, consumes, produces, custom.getCondition());
	}

这个方法会对request里面的信息进行匹配,如果都匹配成功了那么会返回一个RequestMappingInfo

for (T mapping : mappings) {
			T match = getMatchingMapping(mapping, request);
			if (match != null) {
				matches.add(new Match(match, this.handlerMethods.get(mapping)));
			}
		}

匹配成功,会将这个匹配信息和对应的handlerMethod绑定到一起放到matches里面

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);
			return bestMatch.handlerMethod;
		}

接着会对返回的matches进行排序,最后会选择最优的handlerMethod进行返回

return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);

如果找到了handlerMethod,那么在getHandlerInternal方法里面会重新创建要给handlerMethod返回

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
		//获得一个处理器链
		HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
		//添加所有的AdaptedInterceptors
		chain.addInterceptors(getAdaptedInterceptors());

		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
		//在mappedInterceptors里面找到拦截当前url的拦截器,添加到链上
		for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {
			if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
				chain.addInterceptor(mappedInterceptor.getInterceptor());
			}
		}

		return chain;
	}

在返回handler时,不仅仅返回的是一个处理器,而是包含了拦截器链的HandlerExecutionChain,在getHandlerExecutionChain方法中,会将找到的处理器,和拦截当前url的拦截器封装后返回

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

然后有了handler,会根据他来找到HandlerAdapter 来执行它

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");
	}

这个方法很简单就是看支不支持执行这个handler,支持就直接返回

if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

在正式处理前,会执行拦截器的方法,他们是在请求处理前执行的

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

下面就会调用HandlerAdapter的handle方法正式处理请求

public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return handleInternal(request, response, (HandlerMethod) handler);
	}

然后调用模板方法handleInternal,在RequestMappingHandlerAdapter里面被实现

		if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
			// Always prevent caching in case of session attribute management.
			checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
		}
		else {
			// Uses configured default cacheSeconds setting.
			checkAndPrepare(request, response, true);
		}

首先初始化了处理器SessionAttributesHandler,会根据是否有注释@SessionAttributesHandler是必须的进行不同方式的检查,使用的是checkAndPrepare方法

protected final void checkAndPrepare(
			HttpServletRequest request, HttpServletResponse response, int cacheSeconds, boolean lastModified)
			throws ServletException {

		// Check whether we should support the request method.
		String method = request.getMethod();
		if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {
			throw new HttpRequestMethodNotSupportedException(
					method, StringUtils.toStringArray(this.supportedMethods));
		}

		// Check whether a session is required.
		if (this.requireSession) {
			if (request.getSession(false) == null) {
				throw new HttpSessionRequiredException("Pre-existing session required but none found");
			}
		}

		// Do declarative cache control.
		// Revalidate if the controller supports last-modified.
		applyCacheSeconds(response, cacheSeconds, lastModified);
	}

在这里面会给response设置过期时间

if (this.synchronizeOnSession) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
					return invokeHandleMethod(request, response, handlerMethod);
				}
			}
		}

		return invokeHandleMethod(request, response, handlerMethod);

接下来根据是否需要同步执行,选择不同的方式执行invokeHandleMethod方法

ServletWebRequest webRequest = new ServletWebRequest(request, response);

首先将request和response封装到了ServletWebRequest

WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);

接着创建WebDataBinderFactory、ModelFactory 、ServletInvocableHandlerMethod

private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
		SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
		Class<?> handlerType = handlerMethod.getBeanType();
		Set<Method> methods = this.modelAttributeCache.get(handlerType);
		if (methods == null) {
			methods = HandlerMethodSelector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
			this.modelAttributeCache.put(handlerType, methods);
		}
		List<InvocableHandlerMethod> attrMethods = new ArrayList<InvocableHandlerMethod>();
		// Global methods first
		for (Entry<ControllerAdviceBean, Set<Method>> entry : this.modelAttributeAdviceCache.entrySet()) {
			if (entry.getKey().isApplicableToBeanType(handlerType)) {
				Object bean = entry.getKey().resolveBean();
				for (Method method : entry.getValue()) {
					attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
				}
			}
		}
		for (Method method : methods) {
			Object bean = handlerMethod.getBean();
			attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
		}
		return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
	}

在创建ModelFactory的时候,先获取到了处理注释了@SessionAttribute的处理器,然后找到了注释了@ModelAttribute的 方法(在这里是replaceSensitiveWords方法),封装成attrMethods,最后将这些信息封装到ModelFactory中返回

ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

回到invokeHandleMethod方法中,创建了ModelAndViewContainer,将flashMap中所有的参数放到mav里面,调用initModel方法,设置ignoreDefaultModelOnRedirect属性

public void initModel(NativeWebRequest request, ModelAndViewContainer mavContainer, HandlerMethod handlerMethod)
			throws Exception {

		Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
		mavContainer.mergeAttributes(sessionAttributes);

		invokeModelAttributeMethods(request, mavContainer);

		for (String name : findSessionAttributeArguments(handlerMethod)) {
			if (!mavContainer.containsAttribute(name)) {
				Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
				if (value == null) {
					throw new HttpSessionRequiredException("Expected session attribute '" + name + "'");
				}
				mavContainer.addAttribute(name, value);
			}
		}
	}

在initModel方法中,首先会将sessionAttributes里面所有的属性合并到mav中,然后会执行所有找到的被@ModelAttribute注释的方法,最后会检查同时存在sessionAttributes和@ModelAttribute注释的方法的参数,是否被添加了,如果没有 那么添加到mav中

private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer mavContainer)
			throws Exception {

		while (!this.modelMethods.isEmpty()) {
			InvocableHandlerMethod attrMethod = getNextModelMethod(mavContainer).getHandlerMethod();
			String modelName = attrMethod.getMethodAnnotation(ModelAttribute.class).value();
			if (mavContainer.containsAttribute(modelName)) {
				continue;
			}

			Object returnValue = attrMethod.invokeForRequest(request, mavContainer);

			if (!attrMethod.isVoid()){
				String returnValueName = getNameForReturnValue(returnValue, attrMethod.getReturnType());
				if (!mavContainer.containsAttribute(returnValueName)) {
					mavContainer.addAttribute(returnValueName, returnValue);
				}
			}
		}
	}

invokeModelAttributeMethods会执行所有被@ModelAttribute注释的方法,然后将返回的结果放到mav中

public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		if (logger.isTraceEnabled()) {
			StringBuilder sb = new StringBuilder("Invoking [");
			sb.append(getBeanType().getSimpleName()).append(".");
			sb.append(getMethod().getName()).append("] method with arguments ");
			sb.append(Arrays.asList(args));
			logger.trace(sb.toString());
		}
		Object returnValue = doInvoke(args);
		if (logger.isTraceEnabled()) {
			logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");
		}
		return returnValue;
	}

invokeForRequest执行的时候就用到了参数解析器获取request里面的参数,最后执行方法将结果返回,回到invokeHandleMethod方法中

requestMappingMethod.invokeAndHandle(webRequest, mavContainer);

然后会调用requestMappingMethod.invokeAndHandle方法执行我们的doComment方法

Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);

在invokeAndHandle里面也是调用了invokeForRequest来执行方法只不过这次comment的值由于被@ModelAttribute注释的方法处理了,已经变成了其他的值,处理完后会返回值:redirect:/showArticle

public void handleReturnValue(Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

		HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType);
		Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]");
		handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
	}

调用handleReturnValue方法来处理返回的结果,首先根据结果的类型找到对应的处理器,然后使用处理器调用handleReturnValue方法来对返回结果进行处理

public void handleReturnValue(Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

		if (returnValue == null) {
			return;
		}
		else if (returnValue instanceof String) {
			String viewName = (String) returnValue;
			mavContainer.setViewName(viewName);
			if (isRedirectViewName(viewName)) {
				mavContainer.setRedirectModelScenario(true);
			}
		}
		else {
			// should not happen
			throw new UnsupportedOperationException("Unexpected return type: " +
					returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
		}
	}

处理方式很简单,就是将返回值变成viewName,设置到mav中,但是由于我们的是跳转,还会将mav的RedirectModelScenario属性设置为true

return getModelAndView(mavContainer, modelFactory, webRequest);

方法执行完后,会调用getModelAndView方法返回一个ModelAndView

modelFactory.updateModel(webRequest, mavContainer);

首先就会更新model里面存储的值

public void updateModel(NativeWebRequest request, ModelAndViewContainer mavContainer) throws Exception {
		ModelMap defaultModel = mavContainer.getDefaultModel();
		if (mavContainer.getSessionStatus().isComplete()){
			this.sessionAttributesHandler.cleanupAttributes(request);
		}
		else {
			this.sessionAttributesHandler.storeAttributes(request, defaultModel);
		}
		if (!mavContainer.isRequestHandled() && mavContainer.getModel() == defaultModel) {
			updateBindingResult(request, defaultModel);
		}
	}

如果执行了SessionStatus#setCompelte方法,会清空SessionAttributes,否则会将SessionAttribute里面的参数从model中提取出来放到SessionAttributes里面,然后,如果当前不是跳转的方法会在model中为一些参数设置上bindingResult

ModelMap model = mavContainer.getModel();
		ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
		if (!mavContainer.isViewReference()) {
			mav.setView((View) mavContainer.getView());
		}
		if (model instanceof RedirectAttributes) {
			Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
			HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
			RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
		}
		return mav;

接下来,会新创建一个ModelAndView,由于我们的返回值是跳转,所有还不能马上返回需要进一步处理,首先获取FlashAttributes,和request,将FlashAttributes里面的属性都放到OutputFlashMap中供跳转后的方法使用
HandlerAdapter的工作完成了回到doDispatch方法

mappedHandler.applyPostHandle(processedRequest, response, mv);

执行拦截器的方法,到这没有问题的话接下来就需要processDispatchResult来处理

processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
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);
			}
		}

首先检查有没有初五,如果有需要给exception生成一个ModelAndView

render(mv, request, response);

接下来调用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.
			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;
		}
	}

render的主要工作是找到处理当前ModelAndView的View进行渲染

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);
	}

在这里面调用了renderMergedOutputModel方法,renderMergedOutputModel将request属性中保存的outputFlashMap和FlashMapManager取出,使用FlashMapManager将outFlashMap保存到Session中,然后调用sendRedirect方法使用resposne的sendRedirect方法将请求发出,然后返回到processDispatchResult方法中

mappedHandler.triggerAfterCompletion(request, response, null);

调用拦截器的afterCompletion方法,然后将请求返回到DispatcherServlet,在FrameworkServlet的processRequest方法中将原来的LocaleContext和RequestAttributes的值恢复,并发出ServletRequestHandledEvent消息,最后将请求返回给Servlet容器

猜你喜欢

转载自blog.csdn.net/m0_37343985/article/details/84451516