SpringMVC源码分析(四)请求流程分析

a、http请求是怎么被Controller接受处理,然后返回结果的?

发出HTTP请求后,跳过网络层的东西,当被应用服务器Tomcat接受的时候。在Tomcat中存在一个servlet容器,它负责管理所有的servlet,包括SpringMVC的核心组件DispatcherServlet。
请求进入到HttpServlet的service方法中后。service方法会根据 HTTP 请求是 GET、POST、PUT 还是 DELETE 等,进一步调用 Servlet 的 doGet(),doPost(),doPut(),doDelete() 等方法。
1、HttpServlet# service()
2、FrameworkServlet# doGet() 或 doPost() 或 doPut() 或 doDelete()
3、FrameworkServlet# processRequest()

SpringMVC源码分析(四)请求流程分析_第1张图片
SpringMVC源码分析(四)请求流程分析_第2张图片

1、HttpServlet#service()

HttpServletRequest 和 HttpServletResponse 对象是由 Servlet 容器(Tomcat)在调用 Servlet 的 service() 方法之前创建和初始化的。
最终所有的请求都会走到FrameworkServlet的processRequest()中

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

1.2 FrameworkServlet#doPost()

1.2 FrameworkServlet#doGet()

1.2 FrameworkServlet#doPut()

1.2 FrameworkServlet#doDelete()

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

		processRequest(request, response);
	}

	/**
	 * Delegate POST requests to {@link #processRequest}.
	 * @see #doService
	 */
	@Override
	protected final void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

	/**
	 * Delegate PUT requests to {@link #processRequest}.
	 * @see #doService
	 */
	@Override
	protected final void doPut(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

	/**
	 * Delegate DELETE requests to {@link #processRequest}.
	 * @see #doService
	 */
	@Override
	protected final void doDelete(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

1.3 FrameworkServlet# processRequest()

在processRequest(request, response)方法中,主要执行了如下步骤:
【1】获得当前和最新request中的国际化上下文LocaleContext;
【2】获得当前和最新request中的请求参数RequestAttributes;
【3】初始化异步请求管理器WebAsyncManager;
【4】将最新request中的“国际化上下文”和“请求参数”设置到当前线程的上下文中,在整个doService共享,在finally后删除。
【5】doService()处理Http请求;
【6】将当前线程上下文中的“国际化上下文”和“请求参数”还原为之前的值;
【7】无论成功与否,都会发布ServletRequestHandledEvent事件;

protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    long startTime = System.currentTimeMillis();
    Throwable failureCause = null;
    
    // 针对【国际化上下文】,获得当前的LocaleContext和最新request请求中的LocaleContext
    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); 
    LocaleContext localeContext = buildLocaleContext(request);

    // 针对【请求参数】,获得当前的RequestAttributes和最新request请求中的RequestAttributes
    RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
    ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

    // 初始化【异步请求管理器】
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

    // 将request中最新的“国际化上下文”和“请求参数”设置到当前线程的上下文中
    initContextHolders(request, localeContext, requestAttributes);
    
    try {
        /** 处理请求 */
        doService(request, response); 
    }
    catch (ServletException | IOException ex) {...}
    catch (Throwable ex) {...}
    finally {
        // 还原以前的国际化上下文和请求参数设置到当前线程的上下文中
        resetContextHolders(request, previousLocaleContext, previousAttributes);
        if (requestAttributes != null) requestAttributes.requestCompleted();

        // 无论成功与否,都会发布ServletRequestHandledEvent事件
        publishRequestHandledEvent(request, response, startTime, failureCause);
    }
}

2、doService(request, response)

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    Map<String, Object> attributesSnapshot = null;

    /** 在include请求时保存请求属性的快照,以便在include请求后恢复原始属性 */
    if (WebUtils.isIncludeRequest(request)) { 
    // 确定给定的请求是否是一个include请求(判断方法:request中是否存在“javax.servlet.include.request_uri”的属性参数)
        attributesSnapshot = new HashMap<>();
        Enumeration<?> attrNames = request.getAttributeNames();
        while (attrNames.hasMoreElements()) {
            String attrName = (String) attrNames.nextElement();
            // DEFAULT_STRATEGIES_PREFIX="org.springframework.web.servlet"
            if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) 
                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());
    if (this.flashMapManager != null) {
        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);
    }
    RequestPath previousRequestPath = null;
    if (this.parseRequestPath) {
        previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);
        ServletRequestPathUtils.parseAndCache(request); // request.setAttribute(PATH_ATTRIBUTE, requestPath);
    }

    /** 处理Http请求 */
    try {
        doDispatch(request, response);
    }
    finally {
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            if (attributesSnapshot != null) 
                restoreAttributesAfterInclude(request, attributesSnapshot); // include请求后恢复原始属性
        }
        if (this.parseRequestPath) 
            ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request); // 还原请求参数中PATH_ATTRIBUTE的值
    }
}

3、doDispatch(request, response)

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 {
            //如果是Multipart请求,则将request转换为MultipartHttpServletRequest类型 */
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            /**根据request,寻找匹配的Handler */
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response); // 如果没找到,则抛出异常或者返回404
                return;
            }
            
            /**根据Handler,寻找匹配的HandlerAdapter */
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
            String method = request.getMethod();
            boolean isGet = HttpMethod.GET.matches(method);
            if (isGet || HttpMethod.HEAD.matches(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) return;
            }

            /**调用已注册的拦截器列表interceptors的preHandle方法 */
            if (!mappedHandler.applyPreHandle(processedRequest, response)) return;
            
            /**处理请求的逻辑并返回ModelAndView */
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
            
            if (asyncManager.isConcurrentHandlingStarted()) return;

            //如果没有视图View,则向mv中设置默认的视图名称
            applyDefaultViewName(processedRequest, mv);

            //调用已注册的拦截器列表interceptors的postHandle方法
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
        //	省略代码
        }
        catch (Throwable err) {
        //省略代码
        }
        /**调用handler以及处理返回的结果,该结果要么是ModelAndView,要么就是一个需要解析到ModelAndView的异常 */
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
    //省略代码
    }
    catch (Throwable err) {
    //省略代码
    }
    finally {
    //省略代码
    }
}

3.1 getHandler(request)

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    /** 2.1.1 试图从request请求中获取handler实例 **/
    Object handler = getHandlerInternal(request);
    if (handler == null) handler = getDefaultHandler(); // 如果获取不到,则获取默认handler,
    if (handler == null) return null; // 如果仍然获取不到,则直接返回null
    
    // 如果上面获取到的header是字符串类型的beanName,则从IOC中获取到对应的bean
    if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = obtainApplicationContext().getBean(handlerName);
    }
    
    // 确保拦截器等的缓存查找路径(lookupPath)的存在
    if (!ServletRequestPathUtils.hasCachedPath(request)) 
        initLookupPath(request);

    /** 2.1.2 将配置中对应的拦截器加入到执行链中,以确保拦截器生效 */
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

    // 针对CORS(跨域)请求,进行特殊处理
    if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
        CorsConfiguration config = getCorsConfiguration(handler, request);
        if (getCorsConfigurationSource() != null) {
            CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
            config = (globalConfig != null ? globalConfig.combine(config) : config);
        }
        if (config != null) {
            config.validateAllowCredentials();
        }
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }
    
    return executionChain;
}

3.1.1 getHandlerInternal(request)

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
    try {
        return super.getHandlerInternal(request); // 调用AbstractHandlerMethodMapping的getHandlerInternal方法
    }
    finally {
        ProducesRequestCondition.clearMediaTypesAttribute(request);
    }
}
> AbstractHandlerMethodMapping#getHandlerInternal(request)
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    /**【步骤1】从request中寻找请求路径 */
    String lookupPath = initLookupPath(request); // eg: lookupPath="/hello"
    this.mappingRegistry.acquireReadLock();
    try {
        /**【步骤2】通过lookupPath和request,获得请求待流转的方法handlerMethod */
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        this.mappingRegistry.releaseReadLock();
    }
}

3.1.2、initLookupPath()

// eg: lookupPath="/hello"
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<>();
    /**【步骤1】根据请求路径lookupPath来获得可以匹配处理的方法列表  */
    List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);

    /**【步骤2】从directPathMatches获取匹配的Match实例对象,并保存到matches集合中 */
    if (directPathMatches != null) 
         // 根据request对象,解析出http请求method、参数params,请求headers等信息来创建RequestMappingInfo对象,
         // 然后封装到Match对象中,并保存到matches中 
        addMatchingMappings(directPathMatches, matches, request);
    
    if (matches.isEmpty()) 
        addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);

    /**【步骤3】针对已匹配的Match集合对象进行处理 */
    if (!matches.isEmpty()) {
        Match bestMatch = matches.get(0);
        // 发现匹配上了两个相同的method,则进行特殊处理或者抛出异常
        if (matches.size() > 1) {
            Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
            matches.sort(comparator);
            bestMatch = matches.get(0);

            if (CorsUtils.isPreFlightRequest(request)) 
                for (Match match : matches) 
                    if (match.hasCorsConfig()) return PREFLIGHT_AMBIGUOUS_MATCH;    
            else {
                Match secondBestMatch = matches.get(1);
                if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                    Method m1 = bestMatch.getHandlerMethod().getMethod();
                    Method m2 = secondBestMatch.getHandlerMethod().getMethod();
                    String uri = request.getRequestURI();
                    throw new IllegalStateException("Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
                }
            }
        }
        // eg: bestMatch.getHandlerMethod()=com.muse.springbootdemo.controller.DemoController#hello()
        request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
        handleMatch(bestMatch.mapping, lookupPath, request); // 对request进行附加属性赋值
        return bestMatch.getHandlerMethod(); // 返回com.muse.springbootdemo.controller.DemoController#hello()
    }

    /**【步骤4】没有找到已匹配的Match集合对象,则进行异常抛出等操作 */
    else return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
}
> getMappingsByDirectPath()
// eg:urlPath="/hello"
public List<T> getMappingsByDirectPath(String urlPath) {
    return this.pathLookup.get(urlPath); // eg:return {GET [/hello]}
}

3.1.3、getHandlerExecutionChain(handler, request)

【Object handler】真正处理请求的headler;
【List interceptorList】interceptor拦截器列表;

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    //【步骤1】要么强转HandlerExecutionChain类型,要么新建HandlerExecutionChain实例对象
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
            (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

    //【步骤2】遍历adaptedInterceptors,将符合条件的拦截器加入到chain中
    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
        if (interceptor instanceof MappedInterceptor) {
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            if (mappedInterceptor.matches(request)) 
                chain.addInterceptor(mappedInterceptor.getInterceptor());
        }
        else chain.addInterceptor(interceptor);
    }
    return chain;
}

实现一个自定义的请求拦截器时,可以通过实现HandlerInterceptor接口的方式,这个接口一共有3个方法,分别是针对处理请求之前进行拦截操作的preHandle方法,以及针对处理请求之后进行拦截操作的postHandle方法,和在所有请求处理完毕之后进行额外操作afterCompletion方法,代码如下所示:

public interface HandlerInterceptor {
    // 在处理请求之前进行额外操作
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 
            throws Exception {
        return true;
    }

    // 在处理请求之后进行额外操作
    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
            @Nullable ModelAndView modelAndView) throws Exception {}

    // 在所有请求处理完毕之后进行额外操作
    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
            @Nullable Exception ex) throws Exception {}

}

3.2 getHandlerAdapter(request)

我们会通过逐一遍历根据handlerAdapters集合,通过调用HandlerAdapter的supports(handler)方法,来获取与入参handler相匹配的HandlerAdapter,只要找到了匹配的HandlerAdapter,直接返回即可,不再继续遍历对比.
handlerAdapters默认包含4个HandlerAdapter,分别是:
RequestMappingHandlerAdapter
HandlerFunctionAdapter
HttpRequestHandlerAdapter
SimpleControllerHandlerAdapter

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) 
        for (HandlerAdapter adapter : this.handlerAdapters) 
            if (adapter.supports(handler)) // 寻找到匹配的adapter
                return adapter; // eg: RequestMappingHandlerAdapter@7511

    // 如果没有找到HandlerAdapter,则抛出异常
    throw new ServletException(...);
}

HandlerAdapter接口

public interface HandlerAdapter {
    // 是否匹配该HandlerAdapter
    boolean supports(Object handler);

    // 处理请求,返回结果ModelAndView
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    // 用于请求缓存,已作废
    @Deprecated
    long getLastModified(HttpServletRequest request, Object handler);
}

3.3 handle()

public final ModelAndView handle(HttpServletRequest request, 
                                 HttpServletResponse response, 
                                 Object handler) throws Exception {
    return handleInternal(request, response, (HandlerMethod) handler);
}

3.3.1 handleInternal()

在该方法中,主要是执行了两个步骤:
【步骤1】调用invokeHandlerMethod(request, response, handlerMethod)方法真正的执行请求处理;
【步骤2】对于Header不包含 “Cache-Control”的情况进行特殊处理。

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 {
			// No synchronization on session demanded at all...
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}

		if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
			if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
			}
			else {
				prepareResponse(response);
			}
		}

		return mav;
	}
3.3.1.1 invokeHandlerMethod()

【1】进行实例对象的创建及赋值操作,包含:webRequest、binderFactory、modelFactory、invocableMethod、……
【2】通过invocableMethod.invokeAndHandle(webRequest, mavContainer)方法,进行请求处理;
【3】通过getModelAndView(mavContainer, modelFactory, webRequest)方法,将执行结果封装为ModelAndView实例对象;

protected ModelAndView invokeHandlerMethod(HttpServletRequest request, 
                                           HttpServletResponse response,
                                           HandlerMethod handlerMethod) throws Exception {
    // 创建webRequest
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        // 创建binderFactory和modelFactory
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

        //  创建及设置invocableMethod
        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        if (this.argumentResolvers != null) 
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        if (this.returnValueHandlers != null) 
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        invocableMethod.setDataBinderFactory(binderFactory);
        invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

        // 创建及设置mavContainer
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        modelFactory.initModel(webRequest, mavContainer, invocableMethod);
        mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

        // 创建及设置asyncWebRequest
        AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
        asyncWebRequest.setTimeout(this.asyncRequestTimeout);

        // 创建及设置asyncManager
        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();
            invocableMethod = invocableMethod.wrapConcurrentResult(result);
        }
        
        /** 处理请求,实际执行逻辑的地方 */
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        
        if (asyncManager.isConcurrentHandlingStarted()) return null;

        // 处理请求返回结果,获得ModelAndView
        return getModelAndView(mavContainer, modelFactory, webRequest);
    }
    finally {
        webRequest.requestCompleted();
    }
}
1 invokeAndHandle()
public void invokeAndHandle(ServletWebRequest webRequest, 
                            ModelAndViewContainer mavContainer,
                            Object... providedArgs) throws Exception {
    /** 通过反射请求到具体的Controller上,并获得返回值 */
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);

    // 根据ResponseStatus注释设置响应状态
    setResponseStatus(webRequest);

    // 如果没有返回值
    if (returnValue == null) {
        if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
            disableContentCachingIfNecessary(webRequest);
            mavContainer.setRequestHandled(true);
            return;
        }
    }
    // 如果存在返回相关的响应状态原因
    else if (StringUtils.hasText(getResponseStatusReason())) {
        mavContainer.setRequestHandled(true);
        return;
    }
    mavContainer.setRequestHandled(false);

    /** 针对利用HandlerMethodReturnValueHandler的handleReturnValue方法,对返回值进行处理 */
    try {
        this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer,  webRequest);
    } catch (Exception ex) {throw ex;}
}

/**
 * 根据ResponseStatus注释设置响应状态
 */
private void setResponseStatus(ServletWebRequest webRequest) throws IOException {
    // 获得请求响应状态,如果为null,则直接返回
    HttpStatus status = getResponseStatus();
    if (status == null) return;

    // 获得请求响应response,尝试为response设置失败信息(response.sendError)或者状态码(response.setStatus)
    HttpServletResponse response = webRequest.getResponse();
    if (response != null) {
        String reason = getResponseStatusReason();
        if (StringUtils.hasText(reason)) response.sendError(status.value(), reason);
        else response.setStatus(status.value());
    }
    
    // 被RedirectView获取
    webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status);
}
>>>>>> invokeForRequest()

对request请求中的参数进行解析,转换为方法的入参args,然后再采用反射的方式调用Controller类的所对应的处理方法,获得最终处理后的结果:

public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
        Object... providedArgs) throws Exception {
    /** 解析出请求的入参 **/
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);

    /** 利用反射,调用Controller类的所对应的处理方法 */
    return doInvoke(args);
}

/**
 * 请求参数解析
 */
protected Object[] getMethodArgumentValues(NativeWebRequest request, 
                                           ModelAndViewContainer mavContainer,
                                           Object... providedArgs) throws Exception {
    // 获得http请求中的参数列表,如果没有入参,则直接返回空的入参数组
    MethodParameter[] parameters = getMethodParameters();
    if (ObjectUtils.isEmpty(parameters)) return EMPTY_ARGS;
    
    Object[] args = new Object[parameters.length];
    for (int i = 0; i < parameters.length; i++) {
        MethodParameter parameter = parameters[i];
        parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
        
        // 如果参数属于providedArgs类型,则跳过,不进行解析
        args[i] = findProvidedArgument(parameter, providedArgs);
        if (args[i] != null) continue;

        /** 如果所有resolver解析器都不能解析的话,则直接抛出异常 */
        if (!this.resolvers.supportsParameter(parameter)) throw new IllegalStateException(...);

        /** 进行参数解析操作 */
        try {
            args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
        } catch (Exception ex) {throw ex;}
    }
    return args;
}

/**
 * 通过反射,执行逻辑调用
 */
protected Object doInvoke(Object... args) throws Exception {
    // 获得被桥接的方法,即:用户自定义的方法
    Method method = getBridgedMethod();
    try {
        if (KotlinDetector.isSuspendingFunction(method)) 
            return CoroutinesUtils.invokeSuspendingFunction(method, getBean(), args);

        // 利用反射,调用Controller类中相应的method方法
        return method.invoke(getBean(), args);
    }
    catch (IllegalArgumentException ex) {...}
    catch (InvocationTargetException ex) {...}
}
>>>>>>> supportsParameter(parameter)

该方法主要确定这个入参我们的解析器是否支持解析

public boolean supportsParameter(MethodParameter parameter) {
    // 获取方法参数解析器
    return getArgumentResolver(parameter) != null;
}
>>>>>>> resolveArgument()

在这个方法会依次遍历每个解析器的 supportsParameter(parameter) 方法来寻找可以解析入参parameter的具体解析器实现类resolver,如果找到了主要判断parameter参数是否有解析器可以对其进行解析;

public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
            NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    //【步骤1】获取方法参数解析器
    HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
    if (resolver == null) 
        throw new IllegalArgumentException("Unsupported parameter type ...");

    //【步骤2】执行解析操作
    return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
>>>>>>>> getArgumentResolver() 获取入参解析器

RequestParamMethodArgumentResolver:负责处理@RequestParam
RequestHeaderMethodArgumentResolver:负责处理@RequestHeader
SessionAttributeMethodArgumentResolver:负责处理@SessionAttribute
RequestAttributeMethodArgumentResolver:负责处理@RequestAttribute
RequestResponseBodyMethodProcessor:负责处理@RequestBody

SpringMVC源码分析(四)请求流程分析_第3张图片

/**
 * 获得可以解析parameter参数的方法参数解析器(HandlerMethodArgumentResolver)
 */
private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
    // 如果之前解析过,则直接从缓存中获取
    HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);

    if (result == null) {
        for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
            if (resolver.supportsParameter(parameter)) { // supportsParameter方法是由子类实现的
                result = resolver;
                this.argumentResolverCache.put(parameter, result); // 保存到缓存中
                break;
            }
        }
    }
    return result; 
}
>>>>>> handleReturnValue()

主要寻找可以对结果进行处理的handler实例对象;然后调用handler的handleReturnValue()方法来进行结果的处理。
HandlerMethodReturnValueHandler来处理返回值:
RequestResponseBodyMethodProcessor:处理加了@ResponseBody注解的情况
ViewNameMethodReturnValueHandler:处理没有加@ResponseBody注解并且返回值类型为String的情况
ModelMethodProcessor:处理返回值是Model类型的情况
…等等其他得默认的一些处理器
SpringMVC源码分析(四)请求流程分析_第4张图片

public void handleReturnValue(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: " + ...);

    /** 具体解析操作,由子类负责 */
    handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}

/** 
 * 选择可以对结果进行解析的解析器
 */
private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {
    boolean isAsyncValue = isAsyncReturnValue(value, returnType);
    for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
        if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) 
            continue;
        if (handler.supportsReturnType(returnType)) // 由子类负责实现supportsReturnType方法
            return handler;
    }
    return null;
}
>>>>>>>>>>RequestResponseBodyMethodProcessor#handleReturnValue()

RequestResponseBodyMethodProcessor会处理加了@ResponseBody注解的情况,也是常用的一种。会直接方法返回的结果直接响应给浏览器,返回的结果可能是字符串 ;可能是对象; 可能是Map或者其他形式的。

@ResponseBody
public String test() {
	return "张三";
}
>------------------>默认的4个MessageConverter

SpringMVC会利用HttpMessageConverter来处理;

  1. ByteArrayHttpMessageConverter:处理返回值为字节数组的情况,把字节数组返回给浏览器
  2. StringHttpMessageConverter:处理返回值为字符串的情况,把字符串按指定的编码序列号后返回给浏览器
protected void writeInternal(String str, HttpOutputMessage outputMessage) throws IOException {
    HttpHeaders headers = outputMessage.getHeaders();
    if (this.writeAcceptCharset && headers.get(HttpHeaders.ACCEPT_CHARSET) == null) {
        headers.setAcceptCharset(getAcceptedCharsets());
    }
    Charset charset = getContentTypeCharset(headers.getContentType());
    StreamUtils.copy(str, charset, outputMessage.getBody());
}
  1. SourceHttpMessageConverter:处理返回值为XML对象的情况,比如把DOMSource对象返回给浏览器
  2. AllEncompassingFormHttpMessageConverter:处理返回值为MultiValueMap对象的情况
>------------------>特殊的MappingJackson2HttpMessageConverter

MappingJackson2HttpMessageConverter,这个Converter比较强大,能把String、Map、User对象等等都能转化成JSON格式。

@EnableWebMvc
public class AppConfig implements WebMvcConfigurer {

	@Override
	public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
		MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
		messageConverter.setDefaultCharset(StandardCharsets.UTF_8);
		converters.add(messageConverter);
	}
}
@Override
	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

		mavContainer.setRequestHandled(true);
		ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
		ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

		// Try even with null return value. ResponseBodyAdvice could get involved.
		writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
	}

3.4 processDispatchResult()

private void processDispatchResult(HttpServletRequest request,
                                   HttpServletResponse response,
                                   HandlerExecutionChain mappedHandler, 
                                   ModelAndView mv,
                                   Exception exception) throws Exception {
    boolean errorView = false;

    //【步骤1】如果出现了异常,则进行异常处理
    if (exception != null) {
        if (exception instanceof ModelAndViewDefiningException) 
            mv = ((ModelAndViewDefiningException) exception).getModelAndView();
        else {
            Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
            mv = processHandlerException(request, response, handler, exception);
            errorView = (mv != null);
        }
    }

    //【步骤2】如果存在mv,则对mv进行渲染操作
    if (mv != null && !mv.wasCleared()) {
        render(mv, request, response); /** 执行页面渲染操作 */
        if (errorView) WebUtils.clearErrorRequestAttributes(request);
    }

    if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) return;
    
    if (mappedHandler != null) 
        mappedHandler.triggerAfterCompletion(request, response, null);
}

3.4.1 processHandlerException(request, response, handler, exception)

具体流程见异常处理描述

protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
			@Nullable Object handler, Exception ex) throws Exception {

		// Success and error responses may use different content types
		request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);

		// Check registered HandlerExceptionResolvers...
		ModelAndView exMv = null;
		if (this.handlerExceptionResolvers != null) {
			for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
				exMv = resolver.resolveException(request, response, handler, ex);
				if (exMv != null) {
					break;
				}
			}
		}
		if (exMv != null) {
			if (exMv.isEmpty()) {
				request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
				return null;
			}
			// We might still need view name translation for a plain error model...
			if (!exMv.hasView()) {
				String defaultViewName = getDefaultViewName(request);
				if (defaultViewName != null) {
					exMv.setViewName(defaultViewName);
				}
			}
			if (logger.isTraceEnabled()) {
				logger.trace("Using resolved error view: " + exMv, ex);
			}
			else if (logger.isDebugEnabled()) {
				logger.debug("Using resolved error view: " + exMv);
			}
			WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
			return exMv;
		}

		throw ex;
	}
@Override
	@Nullable
	public ModelAndView resolveException(
			HttpServletRequest request, HttpServletResponse response, @Nullable Object handler, Exception ex) {

		if (shouldApplyTo(request, handler)) {
			prepareResponse(ex, response);
			ModelAndView result = doResolveException(request, response, handler, ex);
			if (result != null) {
				// Print debug message when warn logger is not enabled.
				if (logger.isDebugEnabled() && (this.warnLogger == null || !this.warnLogger.isWarnEnabled())) {
					logger.debug("Resolved [" + ex + "]" + (result.isEmpty() ? "" : " to " + result));
				}
				// Explicitly configured warn logger in logException method.
				logException(ex, request);
			}
			return result;
		}
		else {
			return null;
		}
	}

3.4.2 render(mv, request, response)

尝试获得View实例对象;然后对view对象页面渲染

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) {
			// 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;
		}
	}
3.4.2.1 resolveViewName()

通过resolveViewName()来创建view视图对象,并将其加入到IOC中,其具体实现方式还是遍历每一个视图解析器(ViewResolver),调用其resolverViewName(viewName, locale)方法,尝试获得View视图实例对象,如果获得到了,则直接返回,不需要继续遍历其他的视图解析器了

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

SpringMVC源码分析(四)请求流程分析_第5张图片

@Override
	@Nullable
	public View resolveViewName(String viewName, Locale locale) throws Exception {
		if (!isCache()) {
			return createView(viewName, locale);
		}
		else {
			Object cacheKey = getCacheKey(viewName, locale);
			View view = this.viewAccessCache.get(cacheKey);
			if (view == null) {
				synchronized (this.viewCreationCache) {
					view = this.viewCreationCache.get(cacheKey);
					if (view == null) {
						// Ask the subclass to create the View object.
						view = createView(viewName, locale);
						if (view == null && this.cacheUnresolved) {
							view = UNRESOLVED_VIEW;
						}
						if (view != null) {
							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()

最终创建视图是通过loadView()

@Nullable
	protected View createView(String viewName, Locale locale) throws Exception {
		return loadView(viewName, locale);
	}

@Override
	protected View loadView(String viewName, Locale locale) throws Exception {
		AbstractUrlBasedView view = buildView(viewName);
		View result = applyLifecycleMethods(viewName, view);
		return (view.checkResource(locale) ? result : null);
	}
loadView()->buildView(viewName)
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
		Class<?> viewClass = getViewClass();
		Assert.state(viewClass != null, "No view class");

		AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(viewClass);
		view.setUrl(getPrefix() + viewName + getSuffix());

		String contentType = getContentType();
		if (contentType != null) {
			view.setContentType(contentType);
		}

		view.setRequestContextAttribute(getRequestContextAttribute());
		view.setAttributesMap(getAttributesMap());

		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;
	}
loadView()->applyLifecycleMethods(viewName, view)

initializeBean() ioc的知识了

protected View applyLifecycleMethods(String viewName, AbstractUrlBasedView view) {
		ApplicationContext context = getApplicationContext();
		if (context != null) {
			Object initialized = context.getAutowireCapableBeanFactory().initializeBean(view, viewName);
			if (initialized instanceof View) {
				return (View) initialized;
			}
		}
		return view;
	}
3.4.2.2 view.render(mv.getModelInternal(), request, response)
@Override
	public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
			HttpServletResponse response) throws Exception {

		if (logger.isDebugEnabled()) {
			logger.debug("View " + formatViewName() +
					", model " + (model != null ? model : Collections.emptyMap()) +
					(this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));
		}

		Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
		/** 渲染前的准备操作(可由子类自定义实现)*/
		prepareResponse(request, response);
		/** 将渲染后的视图合并到输出流中(可由子类自定义实现)*/
		renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
	}
1 prepareResponse()
/**
 * 试图View被渲染前的准备操作
 */
protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) {
    setResponseContentType(request, response); // 设置response响应的ContentType
    response.setCharacterEncoding(this.encoding.getJavaName()); // 设置response响应的CharacterEncoding
    if (this.disableCaching) response.addHeader("Cache-Control", "no-store"); // 设置response响应的Cache-Control
}
2 renderMergedOutputModel()
/**
 * 将渲染后的视图合并到输出流中
 */
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) {
    ByteArrayOutputStream temporaryStream = null;
    OutputStream stream;
    //【步骤1】获得相应的输出流
    if (this.updateContentLength) {
        temporaryStream = createTemporaryOutputStream();
        stream = temporaryStream;
    }
    else stream = response.getOutputStream();

    //【步骤2】试图serializationView和filters包装在MappingJacksonValue实例对象中
    Object value = filterAndWrapModel(model, request);

    //【步骤3】将渲染的视图value保存到输出流stream中
    writeContent(stream, value);
    if (temporaryStream != null) 
        writeToResponse(response, temporaryStream);
}

3、总结流程图

SpringMVC源码分析(四)请求流程分析_第6张图片

你可能感兴趣的:(SSM,SpringBoot源码分析,spring,java,mvc)