Spring MVC 执行流程详解

2023-05-16

一、Spring MVC 执行流程

请添加图片描述

  1. 客户端的所有请求都会交给前端控制器DispatcherServlet来处理,DispatcherServlet会负责调用系统的其他模块来完成用户请求的处理;

  2. 即用户发送的请求会先从DispatcherServletdoService()方法开始;在该方法中会先将webApplicationContext、localeResolver、themeResolver等对象添加到request请求的attribute属性中,接着调用doDispatch()方法;

  3. 进入到doDispatch()方法中:

    1. 首先检查请求是否为文件的上传/下载请求(校验的规则是:是否是post并且contenttType是否以multipart为前缀),如果是则将请求包装成MultipartHttpServletRequest

    2. 其次调用getHandler()方法从五个HandlerMapping中找到相应的HandlerMapping对象(以普通HTTP请求为例,HandlerMapping为RequestMappingHandlerMapping),进而获取到该Handler对应的处理链HandlerExecutionChain对象

    3. 其实在获取HandlerExecutionChain时,其内部也获取到了Spring自带的以及我们自定义的MVC拦截器;

    4. 然后通过上面获取到的HandlerExecutionChain对象,进而从四个HandlerAdapter中获取相应的HandlerAdapter处理器适配器(HandlerAdapter是一个适配器,它用统一的接口对各种Handler中的方法进行调用)。

    5. 顺序执行处理链HandlerExecutionChain中的拦截器的preHandle()方法,如果返回false,则倒序执行处理链中之前拦截器的afterCompletion()方法并立即返回。

    6. 接着调用handlerAdapter对象的handle()方法来执行Controller中的方法;

      1> 其中会获取26个参数解析器HandlerMethodArgumentResolver,15个返回值处理器HandlerMethodReturnValueHandler

      2> 最后通过反射,打开Controller相应方法的访问权限,进而调用相应的方法

    7. HandlerAdapter执行完,返回一个ModelAndView给DispatcherServlet;并倒序执行拦截器的postHandle()方法;如果出现异常,则在结果处理中被 HandlerExceptionResolver 解析异常,得到新的ModelAndView对象;

    8. 在返回结果处理中,由于ModelAndView的视图是逻辑视图,DispatcherServlet还要借助ViewResolver完成从逻辑视图到真实视图对象的解析工作

    9. 当得到真正的View视图后,DispatcherServlet会利用模型数据ModelAndView对这个View视图对象进行渲染;

    10. 在返回结果处理中,视图渲染完成返回后,如果没有异常,最后倒序调用处理链中所有拦截器的afterCompletion()方法;如果有异常,则在异常处理中倒序执行所有拦截器的afterCompletion()方法。

    11. 客户端得到响应,可能是一个普通的HTML页面,也可以是XML或JSON字符串,还可以是一张图片或者一个PDF文件。

注:在整个SpringMVC的执行流程中,大量使用了模板方法,比如:HandlerAdapter#handle()方法(具体的handleInternal()逻辑由子类实现),FrameServlet#processRequest()方法(具体的doService()逻辑由子类实现)

以GET请求为例:

@RestController
public class TestController {
    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }
}

在这里插入图片描述

二、源码分析请求执行流程

HTTP请求的入口为 DispatcherServlet,DispatcherServlet继承自FrameworkServlet,在FrameworkServlet的doGet()方法便是GET请求的入口。

在这里插入图片描述

无论是 doGet()、doPost()、doPut()、doDelete() 都会进入到processRequest(request, response)方法处理请求。

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

    long startTime = System.currentTimeMillis();
    Throwable failureCause = null;

    // 构建语言环境
    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
    LocaleContext localeContext = buildLocaleContext(request);

    // 从请求中获取参数
    RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
    // 从servlet中构建参数
    ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

    // 构建web异步管理器
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

    // 初始化上下文信息
    initContextHolders(request, localeContext, requestAttributes);

    try {
        // 决定一个请求过来应该找到哪个Controller
        doService(request, response);
    }
    catch (ServletException | 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();
        }
        logResult(request, response, failureCause, asyncManager);
        publishRequestHandledEvent(request, response, startTime, failureCause);
    }
}

由于FrameworkServletdoService()是一个抽象方法(这样看processRequest()也是用了模板方法设计模式),我们去DispatcherServlet中看具体的实现

1)doService()

@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    logRequest(request);

    // request请求添加属性
    ......

    // 将请求的跳转信息保存起来(Controller的return是return到一个接口)
    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);
    }

    try {
        //真正分发请求的地方
        doDispatch(request, response);
    }
    finally {
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            // Restore the original attribute snapshot, in case of an include.
            if (attributesSnapshot != null) {
                restoreAttributesAfterInclude(request, attributesSnapshot);
            }
        }
    }
}

接着进入到doDispatch(request, response)方法,它是整个处理的核心。

2)doDispatch()

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;

    // web异步处理管理类
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {
        // 定义最后返回的ModelAndView视图
        ModelAndView mv = null;
        Exception dispatchException = null;

        try {
            // Case1、检查请求是否为上传/下载请求
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // Case2、从handlerMappings中获取请求对应的处理器执行链HandlerExecutionChain
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // Case3、从handlerAdapters中获取请求的适配器`HandlerAdapter`
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // Process last-modified header, if supported by the handler.
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }

            // 执行HandlerExecutionHandler处理链中拦截器的preHandle()方法,如果返回false,则倒序执行之前的afterCompletion()方法并立即返回
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // Case1--Case3都为准备阶段
            // Case4、真正执行请求适配器HandlerAdapter
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }

            applyDefaultViewName(processedRequest, mv);
            // 执行HandlerExecutionHandler处理链中拦截器的postHandle()方法
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        catch (Throwable err) {
            // As of 4.3, we're processing Errors thrown from handler methods as well,
            // making them available for @ExceptionHandler methods and other scenarios.
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        // 对返回结果进行处理
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                               new NestedServletException("Handler processing failed", err));
    }
    finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            // Instead of postHandle and afterCompletion
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        }
        else {
            // Clean up any resources used by a multipart request.
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
}

Case2: 通过getHandler()方法获取请求对应的处理器执行链 HandlerExecutionChain;

3)getHandler()

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 在Spring初始化的时候会加载所有的handlerMappings
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            // 获取请求对应的HandlerExecutionChain
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

1> 获取所有HandlerMapping类型的Bean:

Spring启动时会加载五个HandlerMapping类型的Bean到IOC容器中,分别为:

  1. requestMappingHandlerMapping
  2. beanNameHandlerMapping
  3. routerFunctionMapping
  4. resourceHandlerMapping
  5. welcomePageHandlerMapping

其中针对HTTP GET、POST普通请求而言,我们主要看requestMappingHandlerMapping,其中包含所有注册的可以处理的请求、以及请求与相应类/方法的映射Mapping。

2> 以普通的GET、POST请求为例,通过RequestMappingHandlerMapping获取请求对应的HandlerExecutionChain

getHandler()方法是如何获取到具体的HandlerExecutionChain的?

RequestMappingHandlerMapping的继承结构:

进入到AbstractHandlerMapping# getHandler()方法看具体的获取HandlerExecutionChain逻辑;

@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 1、获取请求对应的HandlerMethod
    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 = obtainApplicationContext().getBean(handlerName);
    }

    // 2、获取请求对应的 HandlerExecutionChain(默认添加两个拦截器)
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

    if (logger.isTraceEnabled()) {
        logger.trace("Mapped to " + handler);
    }
    else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
        logger.debug("Mapped to " + executionChain.getHandler());
    }

    if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
        CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        config = (config != null ? config.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }

    return executionChain;
}

1> 获取请求对应的 HandlerMethod:

/**
 * AbstractHandlerMethodMapping#getHandlerInternal()方法
 */
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    // 从请求中获取请求的路径
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    request.setAttribute(LOOKUP_PATH, lookupPath);
    this.mappingRegistry.acquireReadLock();
    try {
        // 根据请求路径查找相应的HandlerMethod
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        this.mappingRegistry.releaseReadLock();
    }
}

AbstractHandlerMethodMapping中的属性 mappingRegistry 是一个大容器:

这里内部类 MappingRegistry 中的泛型和外部类 AbstractHandlerMethodMapping<T>的一致,由类定义 public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> 可知,这里的泛型为 RequestMappingInfo

这里先从请求中获取请求的路径,然后根据请求路径和请求通过lookupHandlerMethod()方法获取HandlerMathod

@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<>();
    // 从mappingRegistry的urlLookup中根据urlPath获取匹配的请求路径
    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        // 找到匹配的请求路径,则添加到matches集合中
        addMatchingMappings(directPathMatches, matches, request);
    }
    if (matches.isEmpty()) {
        // No choice but to go through all mappings...
        addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    }

    if (!matches.isEmpty()) {
        Match bestMatch = matches.get(0);
        if (matches.size() > 1) {
            Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
            matches.sort(comparator);
            bestMatch = matches.get(0);
            if (logger.isTraceEnabled()) {
                logger.trace(matches.size() + " matching mappings: " + matches);
            }
            if (CorsUtils.isPreFlightRequest(request)) {
                return PREFLIGHT_AMBIGUOUS_MATCH;
            }
            Match secondBestMatch = matches.get(1);
            if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                Method m1 = bestMatch.handlerMethod.getMethod();
                Method m2 = secondBestMatch.handlerMethod.getMethod();
                String uri = request.getRequestURI();
                throw new IllegalStateException(
                    "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
            }
        }
        request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
        handleMatch(bestMatch.mapping, lookupPath, request);
        return bestMatch.handlerMethod;
    }
    else {
        return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    }
}

phase1:从 mappingRegistry 的属性 urlLookup 中根据请求路径 urlPath 获取匹配的请求信息(this.mappingRegistry.getMappingsByUrl(lookupPath)):

public List<T> getMappingsByUrl(String urlPath) {
    return this.urlLookup.get(urlPath);
}

phase2:如果获取到多个HandlerMethod,从所有匹配的HandlerMethod中找出一个最匹配的(bestMatch)。

2> 获取请求对应的执行链HandlerExecutionChain(默认添加两个拦截器):

也就是添加一些拦截器对请求执行过滤、拦截。

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
                                   (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
        if (interceptor instanceof MappedInterceptor) {
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }
        else {
            chain.addInterceptor(interceptor);
        }
    }
    return chain;
}

其中默认添加两个拦截器:

  1. ConversionServiceExposingInterceptor
  2. ResourceUrlProviderExposingInterceptor

Case3: 获取完请求对应的HandlerExecutionChain之后,通过getHandlerAdapter()进一步获取请求的适配器HandlerAdapter

4)getHandlerAdapter()

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        // 1、获取所有HandlerAdapter类型的bean
        for (HandlerAdapter adapter : this.handlerAdapters) {
            // 找到具体HandlerAdapter
            if (adapter.supports(handler)) {
                return adapter;
            }
        }
    }
    throw new ServletException("No adapter for handler [" + handler +
                               "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

1> 获取所有HandlerAdapter类型的Bean:

Spring启动时会加载四个HandlerAdapter类型的Bean到IOC容器中,分别为:

  1. RequestMappingHandlerAdapter,HTTP请求的HandlerAdapter
  2. HandlerFunctionAdapter
  3. HttpRequestHandlerAdapter
  4. SimpleControllerHandlerAdapter

2> 找到符合相应 HandlerMethod 的 HandlerAdapter:

HandlerAdapter#supports()方法本质上就是一个instanceof类型判断,以RequestMappingHandlerAdapter为例:

@Override
public boolean supports(Object handler) {
	return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler)));
}

Case4: 通过 HandlerAdapter#handle() 方法开始真正执行请求;

5)HandlerAdapter#handle()

进入到父类 AbstractHandlerMethodAdapter#handle()方法

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

这里AbstractHandlerMethodAdapter#handleInternal()又是一个抽象方法,即上层handle()方法是一个模板方法

@Nullable
protected abstract ModelAndView handleInternal(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;

对于HTTP请求,会进入到AbstractHandlerMethodAdapter的子类RequestMappingHandlerAdapter#handlerInternal()方法:

@Override
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 {
        // 真正执行适配器adapter的方法
        // 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;
}

进入到invokeHandlerMethod()方法,这里触发handler中的处理方法

6)RequestMappingHandlerAdapter#invokeHandlerMethod()

@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
                                           HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        // 解析请求的参数,参数解析器HandlerMethodArgumentResolverComposite有26个
        if (this.argumentResolvers != null) {
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        }
        // 返回值处理器
        if (this.returnValueHandlers != null) {
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        }
        // 一堆赋值操作
        .....

        // 调用方法,然后执行
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }

        return getModelAndView(mavContainer, modelFactory, webRequest);
    }
    finally {
        webRequest.requestCompleted();
    }
}

phase1:获取参数解析器 HandlerMethodArgumentResolver;

参数解析器 HandlerMethodArgumentResolver包含两个方法,分别为

  • supportsParameter() —> 判断参数parameter是否可以被当前HandlerMethodArgumentResolver解析
  • resolveArgument() —> 解析参数
public interface HandlerMethodArgumentResolver {
    // 判断parameter是否可以被xxArgumentResolver解析
    boolean supportsParameter(MethodParameter parameter);

    @Nullable
    // 方法参数解析的主要逻辑
    @Nullable
    Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
                           NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
  • 方法参数解析器argumentResolvers一共有26个:
    在这里插入图片描述

phase2:获取返回值/结果处理器HandlerMethodReturnValueHandler;

返回值/结果处理器HandlerMethodReturnValueHandler包含两个方法,分别为

  • supportsReturnType() —> 判断返回值是否可以被当前HandlerMethodReturnValueHandler处理
  • handleReturnValue() —> 处理返回值
public interface HandlerMethodReturnValueHandler {
    //xxMethodReturnValueHandler是否能处理这个returnType
    boolean supportsReturnType(MethodParameter returnType);

    // 处理返回值
    void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
                           ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
  • 返回值/结果处理器一共有15个:
    在这里插入图片描述

phase3:执行方法;

进入到ServletInvocableHandlerMethod#invokeAndHandle(webRequest, mavContainer)方法;

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
                            Object... providedArgs) throws Exception {

    // 真正执行请求的地方
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    // 下面全部为处理返回结果
    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);
    Assert.state(this.returnValueHandlers != null, "No return value handlers");
    try {
        this.returnValueHandlers.handleReturnValue(
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    }
    catch (Exception ex) {
        if (logger.isTraceEnabled()) {
            logger.trace(formatErrorForReturnValue(returnValue), ex);
        }
        throw ex;
    }
}

接着看ServletInvocableHandlerMethod#invokeForRequest()方法

@Nullable
public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
                               Object... providedArgs) throws Exception {
    // 获取方法的入参
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
    if (logger.isTraceEnabled()) {
        logger.trace("Arguments: " + Arrays.toString(args));
    }
    // 调用真正的Controller
    return doInvoke(args);
}

再看doInvoke()方法

  • 通过反射、打开Controller相应方法的访问权限,进而调用相应的方法。
@Nullable
protected Object doInvoke(Object... args) throws Exception {
    // 获得被桥接的⽅法(如果是桥接方法,则返回被桥接的方法,否则直接返回 getMethod()),然后打开访问权限
    ReflectionUtils.makeAccessible(getBridgedMethod());
    try {
        //  通过反射,调⽤Controller中相应的⽅法
        return getBridgedMethod().invoke(getBean(), args);
    }
    catch (IllegalArgumentException ex) {
        ......
    }
}

最后再回到 DispatcherServlet#doDispatch() 方法中,看其调用 processDispatchResult() 方法如何处理返回结果

7)processDispatchResult()

这里会进行异常的处理、视图的渲染、以及HandlerAdapter中所有拦截器的 afterCompletion() 方法。

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
		@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
		@Nullable Exception exception) throws Exception {

	boolean errorView = false;

	/** 如果发生了异常,对异常进行处理 */
	if (exception != null) {
		if (exception instanceof ModelAndViewDefiningException) {
			logger.debug("ModelAndViewDefiningException encountered", exception);
			mv = ((ModelAndViewDefiningException) exception).getModelAndView();
		}
		else {
			Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
			mv = processHandlerException(request, response, handler, exception);
			errorView = (mv != null);
		}
	}

	/** 处理程序是否返回要渲染的视图? */
	if (mv != null && !mv.wasCleared()) {
		/** 进行视图渲染 */
		// eg3:
		render(mv, request, response);
		if (errorView) {
			WebUtils.clearErrorRequestAttributes(request);
		}
	}
	else {
		if (logger.isTraceEnabled()) {
			logger.trace("No view rendering, null ModelAndView returned.");
		}
	}

	if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
		// Concurrent handling started during a forward
		return;
	}

    // 执行HandlerExecutionChain中拦截器的afterCompletion()方法
	if (mappedHandler != null) {
		mappedHandler.triggerAfterCompletion(request, response, null);
	}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring MVC 执行流程详解 的相关文章

随机推荐

  • 深度学习及mmdetection学习理解笔记

    关于mmdet源码 mmdetection 的网络配置中 type参数都是实例化的类名 后面的都是对于的类初始化参数 参考 MMCV 核心组件分析 五 Registry 详解 MMDetection 使用技巧和源码实现 关于卷积 1x1 的
  • python学习——Anaconda及TensorFlow-GPU版本安装

    1 下载安装Anaconda 官网的下载会很慢 xff0c 可以在这里下载 http download zol com cn detail 45 448706 shtml 然后运行安装包 xff0c 一路默认安装 xff0c 直到这一步 x
  • python学习——绘制loss、acc学习曲线

    两种方式 1 直接画 model fit返回acc和loss的日志 hist 61 model fit train data train label batch size 61 64 epochs 61 2 validation split
  • python学习——读取txt文件数据并画图

    1 读取txt xff0c 准备数据 这里主要用到列表list的split 函数 xff0c 先简单举个例子 xff1a 要从line字符串中提取1 598912和2 104217两个数据 line 61 39 step 0 dis los
  • 安卓利用tensorflow-lite使用yolov5训练的模型

    前言 作为使用yolov5后一次简单的尝试 准备工作 通过yolov5训练出自己所需要的模型查看模型训练教程将模型通过tensorflow的python版转换 xff0c 使用yolov5 6 1以上版本安卓端引入tensorflow远端依
  • 多个生产者一个消费者的单线程处理队列

    之前其他博主那里看到的例子 xff0c 很值得参考 span class token comment lt summary gt span span class token comment 队列处理 span span class toke
  • No plugin found for prefix install in the current project解决方案

    No plugin found for prefix install in the current project解决方案 maven 使用的setting配置文件为默认配置文件 xff0c 未修改 xff0c 运行install时报如下错
  • ubuntu 16和ubuntu20如何直接使用root登录系统

    之前Ubuntu14好像还可以直接选择用户名为root进行root登陆 xff0c 后面的版本好像就不行了 xff0c 不能选择root登陆了 没有root权限 xff0c 操作的时候好多情况都需要切换root权限进行操作 xff0c 这样
  • Kali 安装vnc

    1 安装tightvnc apt install tightvncserver apt install tightvnc java 通过浏览器java访问需要安装tightvnc java 2 启动VNC服务 span class toke
  • 通俗易懂的zookeeper选举机制

    目前网络上已有很多文章讲解了zookeeper的选举机制 xff0c 但都比较抽象难懂 xff0c 于是写下此文 xff0c 用最通俗易懂的语言阐述zookeeper的选举机制 xff0c 希望能帮助大家理解 zookeeper的选举机制一
  • mybatis IncompleteElementException:Could not find result map java.lang.String

    MyBatis项目中在查询数据库时遇到org apache ibatis builder IncompleteElementException Could not find result map java lang String 原因了把r
  • 【JAVA】-判断链表是否包含环

    目录 一 问题二 解题思路三 解题代码 一 问题 判断链表是否包含环 二 解题思路 判断链表是否包含环属于经典问题了 xff0c 解决方案也是用快慢指针 xff1a 每当慢指针 slow 前进一步 xff0c 快指针 fast 就前进两步
  • FTPClient 中文目录、中文文件名乱码、上传文件失败 解决方法

    FTPClient上传中文目录 中文文件名乱码问题解决方法 本文使用的FTP工具包为 apache的 commons net 起因 xff1a 今天在做FTP上传时一直上传文件上传不了 xff0c xff08 代码是跑通了 xff0c 但是
  • maven idea设置查找依赖优先从本地仓库获取

    第一步 xff1a 在这个settings里面 xff0c 设置默认的 第二步设置参数 DarchetypeCatalog 61 internal
  • Android集成OpenCV(NDK)

    1 下载OpenCv的动态库 so OpenCv官网 这边下载的是4 6 0 2 解压opencv 4 6 0 android sdk zip 复制目录opencv 4 6 0 android sdk OpenCV android sdk
  • Win10 重装系统备忘

    文章目录 一 美化工具1 Dism 43 43 很方便的简化 34 资源管理器 34 xff0c 比网上的教程方便很多 还有右键菜单等等 2 StartIsBack 可以吧 34 Win10菜单栏 34 xff08 屏幕下面那一横排 xff
  • ubuntu无法打开terminal

    我是在将系统显示设置为中文显示后 xff0c 重启无法打开终端的 xff0c 可以按照下面的链接进行修改 http blog csdn net u010395144 article details 52794947
  • MariaDB用法——增删改查

    数据库四大护法 增insert 删delete 改update 查select 设置禁用mysql删除语句 xff0c 防止操作者误删数据 mysql secure installation mysql基础安全设置 xff0c 设置密码 c
  • 女生学Java好不好就业?看看学完Java的你就业道路有多广?

    技能总在将学未学时最为美好 xff0c 高薪可期 Java xff0c 这门于 1995 年正式发布的老牌编程语言 xff0c 在每年 Github 的开发者报告统计出来之时 xff0c 总居前三高位不下 xff0c 成为使用人数最多的编程
  • Spring MVC 执行流程详解

    一 Spring MVC 执行流程 客户端的所有请求都会交给前端控制器DispatcherServlet来处理 xff0c DispatcherServlet会负责调用系统的其他模块来完成用户请求的处理 xff1b 即用户发送的请求会先从D