二.SpringMVC源码剖析-SpringMVC执行流程

本文涉及的产品
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
简介: 上一篇文章写得是SpringMVC组件初始化,这篇文章我们来探讨一下SpringMVC的执行流程

前言

上一篇文章写得是SpringMVC组件初始化,这篇文章我们来探讨一下SpringMVC的执行流程

SpringMVC执行流程

SpringMVC执行流程几乎是在面试时面试官对SpringMVC部分的必问之题,下面是SpirngMVC的执行原理图
在这里插入图片描述
这个是请求在SpringMVC的执行流程

  1. DispatcherServlet:请求打过来由DispatcherServlet处理,它是 SpringMVC 中的前端控制器(中央控制器), 负责接收 Request 并将 Request 转发给对应的处理组件
  2. HandlerMapping:HandlerMapping 维护了 url 和 Controller(Handler)的 映 射关系 。 DispatcherServlet 接 收 请求, 然 后 从 HandlerMapping 查找处理请求的Controller(Handler),标注了@RequestMapping 的每个 method 都可以看成是一个 Handler,HandlerMapping 在请求到达之后, 它的作用便是找到请求相应的处理器 Handler 和 Interceptors。
  3. HandlerAdapter:SpringMVC通过HandlerAdapter对Handler进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。它的作用就是按照特定的规则去执行 Controller (Handler)
  4. Handler : Controller (Handler)负责处理请求,Controller 执行后并返回 ModelAndView 对象,其中包括了数据模型和逻辑视图,,ModelAndView 是封装结果 视图的组件。Handler把结果返回给HandlerAdapter,HandlerAdapter把结果返回给DispatcherServlet前端控制器。
  5. ViewResolver:DispatcherServlet收到ModelAndView,调用视图解析器(ViewResolver)来解析HandlerAdapter传递的ModelAndView。Handler执行完成后返回的是逻辑视图,也就是视图名字,一个String ,还有一个Model就是数据模型,封装成ModelAndView。ViewResolver视图解析的作用就是根据视图名,把本地模板文件(比如:xx.jsp;xx.ftl)解析为View视图对象。View用来渲染视图,也就是负责把Handler返回的数据模型model,填充到模板(jsp;ftl)形成html格式的静态内容。
  6. 最后就是把生成的html通过response写给浏览器,浏览器进行html渲染展示。

核心类认识

开始之前先来认识几个对象,否则下面会晕菜

HandlerMethod :是的controller中方法的封装,其中包括在Controller的Bean对象以及Method方法对象

public class HandlerMethod {
   
   

    /** Logger that is available to subclasses */
    protected final Log logger = LogFactory.getLog(HandlerMethod.class);

    private final Object bean;    //controller对应的bean

    private final Method method;    //方法对象

    private final BeanFactory beanFactory;

    private final MethodParameter[] parameters;

    private final Method bridgedMethod;

MappedInterceptor :对拦截器的封装

public final class MappedInterceptor {
   
   

    private final String[] includePatterns;    

    private final String[] excludePatterns; //排除

    private final HandlerInterceptor interceptor; //拦截器

RequestMappingInfo : 对@Controller和@RequestMapping注解的类的方法进行解析,然后把解析的结果封装成RequestMappingInfo , 对象中包含了针对@RequestMapping注解的6个属性的匹配条件,DispaterServlet需要根据找到请求匹配的Handler就需要满足6个匹配条件。

  • PatternsRequestCondition :模式请求路径过滤器 ,根据request请求路径进行匹配
  • RequestMethodsRequestCondition : 请求方法过滤器,根据request请求方式进行匹配
  • ParamsRequestCondition :请求参数过滤器,根据请求的参数进行匹配
  • HeadersRequestCondition : 请求过滤器 ,根据请求头进行匹配
  • ConsumesRequestCondition :根据 筛选出同请求Accpet匹配的媒体类型表达式列表
  • ProducesRequestCondition :应答媒体类型过滤器,根据请求Content-Type媒体类型进行匹配
  • RequestCondition (optional, custom request condition)
public final class RequestMappingInfo implements RequestCondition<RequestMappingInfo> {
   
   
    //根据url进行匹配
    private final PatternsRequestCondition patternsCondition;
    //方法匹配条件
    private final RequestMethodsRequestCondition methodsCondition;
    //请求参数过滤器,参数匹配条件
    private final ParamsRequestCondition paramsCondition;
    //头字段过滤器,请求头匹配条件
    private final HeadersRequestCondition headersCondition;
   //Consumes匹配条件
    private final ConsumesRequestCondition consumesCondition;
   // Produces匹配条件
    private final ProducesRequestCondition producesCondition;

DispatchServlet执行流程

DispatchServlet是一个Servlet,请求进来会执行 DispatcherServlet#doService 方法

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
   
   
        ...省略...

        // Make framework objects available to handlers and view objects.
        //把容器对象设置到request
        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
        //把localeResolver设置给request
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
        //把themeResolver设置给request
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
        request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

        FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
        if (inputFlashMap != null) {
   
   
            request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
        }
        //设置flashMapManager
        request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

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

DispatcherServlet#doService调用了DispatcherServlet#doDispatch 做请求处理

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   
   
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
        //管理异步请求
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
   
   
            ModelAndView mv = null;
            Exception dispatchException = null;

            try {
   
   
                //1.检查是否是Multipart文件上传
                processedRequest = checkMultipart(request);
                multipartRequestParsed = processedRequest != request;

                // Determine handler for the current request.
                //2.遍历所有 handlerMappings 找到当前请求对应的handler,
                //比如:RequestMappingHandlerMapping 中维护了一个LinkedHashMap类型的handlerMethods,
                //是对HandlerMethod的存储。底层根据URL从handlerMethods匹配一个HandlerMethod,
                //然后把HandlerMethod封装到一个HandlerExecutionChain中
                //HandlerMethod是对controller方法method的封装,
                //这里拿到的是HandlerExecutionChain handler执行链,其中封装了Handler和inteceptor
                mappedHandler = getHandler(processedRequest, false);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
   
   
                    //如果没找到会走404
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // Determine handler adapter for the current request.
                //3.从handlerAdapters中循环,找到支持handler的,处理请求适配器HandlerAdapter(如:RequestMappingHandlerAdapter)
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // Process last-modified header, if supported by the handler.
                //处理lastModified
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
   
   
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
   
   
                        String requestUri = urlPathHelper.getRequestUri(request);
                        logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
   
   
                        return;
                    }
                }
                //4.调用拦截器的preHandle
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
   
   
                    return;
                }

                try {
   
   
                    // Actually invoke the handler.
                    //5.调用 HandlerAdapter 实际执行handler,返回ModelAndView
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                }
                finally {
   
   
                    if (asyncManager.isConcurrentHandlingStarted()) {
   
   
                        return;
                    }
                }
                //6.处理默认的视图名,如果mv != null && !mv.hasView()
                //就会使用RequestToViewNameTranslator#getViewName解析一个默认的view
                applyDefaultViewName(request, mv);
                //7.调用拦截器的postHandle
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
   
   
                dispatchException = ex;
            }
            //8.处理结果,内部会使用viewResolver.resolveViewName渲染视图得到View对象
            //然后执行:View#render方法渲染
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
   
   
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Error err) {
   
   
            triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
        }
        finally {
   
   
            if (asyncManager.isConcurrentHandlingStarted()) {
   
   
                // Instead of postHandle and afterCompletion
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                return;
            }
            // Clean up any resources used by a multipart request.
            if (multipartRequestParsed) {
   
   
                cleanupMultipart(processedRequest);
            }
        }
    }

这里对核心方法做一个解释

查找HandlerMethod

getHandler 方法:该方法是遍历所有 handlerMappings ,找到合适的HandlerMapping,然后通过HandlerMapping#getHandler查找当前请求对应的HandlerMethod。(HandlerMethod是对controller中方法的封装),这里拿到的是HandlerExecutionChain 执行链而不是HandlerMethod,HandlerExecutionChain中封装了HandlerMethod和inteceptor拦截器;见:org.springframework.web.servlet.DispatcherServlet#getHandler(javax.servlet.http.HttpServletRequest)


protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   
   
        for (HandlerMapping hm : this.handlerMappings) {
   
   
            if (logger.isTraceEnabled()) {
   
   
                logger.trace(
                        "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
            }
            //使用HandlerMapping 获取处理请求的Handler,封装到HandlerExecutionChain执行链对象中
            //HandlerExecutionChain包括了HandlerMethod和interceptor拦截器
            HandlerExecutionChain handler = hm.getHandler(request);
            if (handler != null) {
   
   
                return handler;
            }
        }
        return null;
    }

  public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   
   
          //找到Handler
        Object handler = getHandlerInternal(request);
        if (handler == null) {
   
   
            handler = getDefaultHandler();
        }
        if (handler == null) {
   
   
            return null;
        }
        // Bean name or resolved handler?
        if (handler instanceof String) {
   
   
            String handlerName = (String) handler;
            handler = getApplicationContext().getBean(handlerName);
        }
        //把handler封装成HandlerExecutionChain ,其中还包括了拦截器的封装
        return getHandlerExecutionChain(handler, request);
    }

    protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
   
   
        //创建一个Handler执行链对象
        HandlerExecutionChain chain =
            (handler instanceof HandlerExecutionChain) ?
                (HandlerExecutionChain) handler : new HandlerExecutionChain(handler);
        //添加拦截器到HandlerExecutionChain 
        chain.addInterceptors(getAdaptedInterceptors());

        String lookupPath = urlPathHelper.getLookupPathForRequest(request);
        for (MappedInterceptor mappedInterceptor : mappedInterceptors) {
   
   
            if (mappedInterceptor.matches(lookupPath, pathMatcher)) {
   
   
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }

        return chain;
    }

getHandler方法最终会走到org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#getHandlerInternal ,该方法就是根据request查找一个HandlerMethod

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
   
   
        //拿到请求的路径
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        if (logger.isDebugEnabled()) {
   
   
            logger.debug("Looking up handler method for path " + lookupPath);
        }
        //根据请求路径,找到匹配的HandlerMethod
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);

        if (logger.isDebugEnabled()) {
   
   
            if (handlerMethod != null) {
   
   
                logger.debug("Returning handler method [" + handlerMethod + "]");
            }
            else {
   
   
                logger.debug("Did not find handler method for [" + lookupPath + "]");
            }
        }

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

这里在拿到请求的路径,根据请求路径,找到匹配的HandlerMethod,再往里面走

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
   
   
        //matches是requestMppingInfo和HandlerMethod的匹配器集合
        List<Match> matches = new ArrayList<Match>();
        //根据请求的路径,从 this.urlMap中拿到RequestMappingInfo,
        //urlMap 是一个LinkedHashMap,存储了Url路径和RequestMappingInfo的映射关系
        List<T> directPathMatches = this.urlMap.get(lookupPath);
        if (directPathMatches != null) {
   
   
            addMatchingMappings(directPathMatches, matches, request);
        }

        if (matches.isEmpty()) {
   
   
            // No choice but to go through all mappings
            //如果从urlMap中没有找到RequestMappingInfo,那么matches就是空的
            //根据Request对象封装一个requestMppingInfo,然后handlerMethods的keySet中拿到对应的HandlerMethod,(会根据Request中的URL,请求方式,参数params,请求头headers,consumes,produces去匹配handlerMethods.keySet中的requestMppingInfo)
            //然后从handlerMethods根据requestMppingInfo拿到HandlerMethod
            //把requestMppingInfo和HandlerMethod封装成Match添加到matches中
            addMatchingMappings(this.handlerMethods.keySet(), matches, request);
        }

        if (!matches.isEmpty()) {
   
   
            Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
            Collections.sort(matches, comparator);

            if (logger.isTraceEnabled()) {
   
   
                logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
            }

            Match bestMatch = matches.get(0);
            if (matches.size() > 1) {
   
   
                Match secondBestMatch = matches.get(1);
                if (comparator.compare(bestMatch, secondBestMatch) == 0) {
   
   
                    Method m1 = bestMatch.handlerMethod.getMethod();
                    Method m2 = secondBestMatch.handlerMethod.getMethod();
                    throw new IllegalStateException(
                            "Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" +
                            m1 + ", " + m2 + "}");
                }
            }

            handleMatch(bestMatch.mapping, lookupPath, request);
            //从bestMatch拿到Handler
            return bestMatch.handlerMethod;
        }
        else {
   
   
            return handleNoMatch(handlerMethods.keySet(), lookupPath, request);
        }
    }

这里出现了两个集合,urlMap 和 handlerMethods ,urlMap 存储的是url和RequestMappingInfo的映射关系,handlerMethods 存储的是RequestMappingInfo和HandlerMethod的关系。

这里的代码比较复杂,先是从 urlMap中根据url拿到RequestMappingInfo集合然后,如果没获取到即:matches.isEmpty()就会调用addMatchingMappings去处理,有兴趣自己去断点一下,该方法的大致流程如下

  1. 根据request中的url,method,参数params,请求头headers,consumes,produces去创建一个requestMppingInfo
  2. 然后根据requestMppingInfo为key从handlerMethods拿到HandlerMethod封装成Match 对象添加到matches集合中
  3. 从Match 中拿到当前请求对应的HandlerMethod

那么这里的handlerMethods和urlMap 是哪儿来的?

以:RequestMappingHandlerMapping为例在其父类AbstractHandlerMethodMapping中维护了一个 Map<T, HandlerMethod> handlerMethods = new LinkedHashMap<T, HandlerMethod>()该集合中装的就是RequestMappingInfo和HandlerMethod的映射关系,RequestMappingInfo是的RequstMapping的封装,HandlerMethod是对Conroller中方法的封装。初始化流程如下

  1. AbstractHandlerMethodMapping它实现了InitializingBean接口,在RequestMappingHandlerMapping初始化的使用会触发AbstractHandlerMethodMapping#afterPropertiesSet方法
  2. 该方法中会调用AbstractHandlerMethodMapping#initHandlerMethods 初始化HandlerMethod,
    其实就是从容器中拿到所有标识了@Controller或者@RequestMapping注解的Bean,也就是controller,然后拿到其中的所有method封装成HandlerMethod对象,然后再拿到method上RequestMapping信息封装成RquestMappingInfo对象,再把RquestMappingInfo和HandlerMethod以前者为key,后置为value注册到handlerMethods集合中。
  3. 把Url路径和RequestMappingInfo的映射关系存储到AbstractHandlerMethodMapping类中的 MultiValueMap<String, T> urlMap = new LinkedMultiValueMap<String, T>()集合中

这个是在MappingHandlerMapping初始化的时候就把HandlerMethod封装好存储在了handlerMethods 集合中,当请求过来就根据Request去匹配一个RequestMappingInfo,然后再找到对应的HandlerMethod返回。

查找HandlerAdapter

查找HandlerAdapter在org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter中,

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
   
   
        for (HandlerAdapter ha : this.handlerAdapters) {
   
   
            if (logger.isTraceEnabled()) {
   
   
                logger.trace("Testing handler adapter [" + ha + "]");
            }
            if (ha.supports(handler)) {
   
   
                return ha;
            }
        }
        throw new ServletException("No adapter for handler [" + handler +
                "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }

// org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#supports
    public final boolean supports(Object handler) {
   
   
        return handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler);
    }

从handlerAdapters循环所有的HandlerAdapter,调用supports方法判断是否支持该Handler,如果支持就返回HandlerAdapter

调用拦截器的preHandle

代码在org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle方法中,在HandlerExecutionChain维护了一个HandlerInterceptor[] interceptors,存储了所有的拦截器。源码如下

public class HandlerExecutionChain {
   
   

    private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);

    private final Object handler;
    //拦截器数组
    private HandlerInterceptor[] interceptors;
    ...省略...

    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
   
   
        if (getInterceptors() != null) {
   
   
            for (int i = 0; i < getInterceptors().length; i++) {
   
   
            //拿到所有的拦截器,调用preHandle方法
                HandlerInterceptor interceptor = getInterceptors()[i];
                if (!interceptor.preHandle(request, response, this.handler)) {
   
   
                //如果拦截器返回false,即不放行就执行拦截器的afterCompletion方法
                    triggerAfterCompletion(request, response, null);
                    return false;
                }
                this.interceptorIndex = i;
            }
        }
        return true;
    }

调用HandlerAdatapter

找到HanlderMethod之后执行拦截器的preHandler方法,然后执行HandlerAdapter#handle,最终会调用RequestMappingHandlerAdapter#invokeHandleMethod

private ModelAndView invokeHandleMethod(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
   
   
        //把request和response包装到ServletWebRequest对象
        ServletWebRequest webRequest = new ServletWebRequest(request, response);

        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
        ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);
        //ModelAndvView的容器对象,方法调用之后的view和model就会在该容器中
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
        mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

        AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
        asyncWebRequest.setTimeout(this.asyncRequestTimeout);

        final WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.setTaskExecutor(this.taskExecutor);
        asyncManager.setAsyncWebRequest(asyncWebRequest);
        asyncManager.registerCallableInterceptors(this.callableInterceptors);
        asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

        if (asyncManager.hasConcurrentResult()) {
   
   
            Object result = asyncManager.getConcurrentResult();
            mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
            asyncManager.clearConcurrentResult();

            if (logger.isDebugEnabled()) {
   
   
                logger.debug("Found concurrent result value [" + result + "]");
            }
            requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);
        }

        //调用HandlerMethod方法,底层回从HandlerMethod拿到Method,,然后使用反射进行调用
        //把方法返回的viewName和model添加到mavContainer
        requestMappingMethod.invokeAndHandle(webRequest, mavContainer);

        if (asyncManager.isConcurrentHandlingStarted()) {
   
   
            return null;
        }
        //获取ModelAndView,从mavContainer拿到viewName和model生成ModelAndView
        return getModelAndView(mavContainer, modelFactory, webRequest);
    }

invokeAndHandle底层调用该方法nvocableHandlerMethod#invokeForRequest

public final Object invokeForRequest(NativeWebRequest request,
                                     ModelAndViewContainer mavContainer,
                                     Object... providedArgs) throws Exception {
   
   
    //获取方法的参数
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);

    if (logger.isTraceEnabled()) {
   
   
        StringBuilder builder = new StringBuilder("Invoking [");
        builder.append(this.getMethod().getName()).append("] method with arguments ");
        builder.append(Arrays.asList(args));
        logger.trace(builder.toString());
    }
    //传入参数,调用方法
    Object returnValue = invoke(args);

    if (logger.isTraceEnabled()) {
   
   
        logger.trace("Method [" + this.getMethod().getName() + "] returned [" + returnValue + "]");
    }

    return returnValue;
}

private Object invoke(Object... args) throws Exception {
   
   
        ReflectionUtils.makeAccessible(this.getBridgedMethod());
        try {
   
   
            //反射调用方法
            return getBridgedMethod().invoke(getBean(), args);
        }
        catch (IllegalArgumentException e) {
   
   
            String msg = getInvocationErrorMessage(e.getMessage(), args);
            throw new IllegalArgumentException(msg, e);
        }
        catch (InvocationTargetException e) {
   
   
            // Unwrap for HandlerExceptionResolvers ...
            Throwable targetException = e.getTargetException();
            if (targetException instanceof RuntimeException) {
   
   
                throw (RuntimeException) targetException;
            }
            else if (targetException instanceof Error) {
   
   
                throw (Error) targetException;
            }
            else if (targetException instanceof Exception) {
   
   
                throw (Exception) targetException;
            }
            else {
   
   
                String msg = getInvocationErrorMessage("Failed to invoke controller method", args);
                throw new IllegalStateException(msg, targetException);
            }
        }
    }

viewResolver渲染视图

handler调用完成之后,代码来到DispatcherServlet#processDispatchResult负责处理结果

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

        boolean errorView = false;

        if (exception != null) {
   
   
            if (exception instanceof ModelAndViewDefiningException) {
   
   
                logger.debug("ModelAndViewDefiningException encountered", exception);
                mv = ((ModelAndViewDefiningException) exception).getModelAndView();
            }
            else {
   
   
            //这里在调用handlerExceptionResolvers处理异常,会循环所有的handlerExceptionResolvers
            //然后根据exception生成一个ModelAndView
                Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
                mv = processHandlerException(request, response, handler, exception);
                errorView = (mv != null);
            }
        }

        // Did the handler return a view to render?
        if (mv != null && !mv.wasCleared()) {
   
   
        //【重要】渲染视图
            render(mv, request, response);
            if (errorView) {
   
   
                WebUtils.clearErrorRequestAttributes(request);
            }
        }
        else {
   
   
            if (logger.isDebugEnabled()) {
   
   
                logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
                        "': assuming HandlerAdapter completed request handling");
            }
        }

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

        if (mappedHandler != null) {
   
   
            //[重要]执行拦截器的interceptor.afterCompletion
            mappedHandler.triggerAfterCompletion(request, response, null);
        }
    }

代码来到org.springframework.web.servlet.DispatcherServlet#render,该方法负责渲染视图

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
   
   
        // Determine locale for request and apply it to the response.
        Locale locale = this.localeResolver.resolveLocale(request);
        response.setLocale(locale);

        View view;
        if (mv.isReference()) {
   
   
            // We need to resolve the view name.
            //调用视图解析器,解析viewName,得到View对象
            view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
            if (view == null) {
   
   
                throw new ServletException(
                        "Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" +
                                getServletName() + "'");
            }
        }
        else {
   
   
            // No need to lookup: the ModelAndView object contains the actual View object.
            view = mv.getView();
            if (view == null) {
   
   
                throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
                        "View object in servlet with name '" + getServletName() + "'");
            }
        }

        // Delegate to the View object for rendering.
        if (logger.isDebugEnabled()) {
   
   
            logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
        }
        //【重要】调用view.render渲染视图
        view.render(mv.getModelInternal(), request, response);
    }

    protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
            HttpServletRequest request) throws Exception {
   
   
        //调用视图解析器,根据viewName生产一个View
        for (ViewResolver viewResolver : this.viewResolvers) {
   
   
            View view = viewResolver.resolveViewName(viewName, locale);
            if (view != null) {
   
   
                return view;
            }
        }
        return null;
    }

resolveViewName方法循环所有的viewResolvers ,调用viewResolver.resolveViewName根据viewName解析一个View对象,底层调用AbstractCachingViewResolver#resolveViewName创建View,如下

protected AbstractUrlBasedView buildView(String viewName) throws Exception {
   
   
        AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass());
        //前缀+viewName+后缀
        view.setUrl(getPrefix() + viewName + getSuffix());
        String contentType = getContentType();
        if (contentType != null) {
   
   
            view.setContentType(contentType);
        }
        view.setRequestContextAttribute(getRequestContextAttribute());
        view.setAttributesMap(getAttributesMap());
        if (this.exposePathVariables != null) {
   
   
            view.setExposePathVariables(exposePathVariables);
        }
        return view;
    }

找到View之后,会调用View的render方法渲染视图,见:org.springframework.web.servlet.view.AbstractView#render

public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
   
   
        if (logger.isTraceEnabled()) {
   
   
            logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
                " and static attributes " + this.staticAttributes);
        }
        //拿到model数据模型
        Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);

        prepareResponse(request, response);
        //渲染
        renderMergedOutputModel(mergedModel, request, response);
    }

继续跟踪org.springframework.web.servlet.view.InternalResourceView#renderMergedOutputModel方法

protected void renderMergedOutputModel(
            Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
   
   

        // Determine which request handle to expose to the RequestDispatcher.
        HttpServletRequest requestToExpose = getRequestToExpose(request);

        // Expose the model object as request attributes.
        //暴露model对象,把model中的数据设置为request的属性
        exposeModelAsRequestAttributes(model, requestToExpose);

        // Expose helpers as request attributes, if any.
        exposeHelpers(requestToExpose);

        // Determine the path for the request dispatcher.
        //视图中的模板地址 如:WEB-INF/XX.JSP
        String dispatcherPath = prepareForRendering(requestToExpose, response);

        // Obtain a RequestDispatcher for the target resource (typically a JSP).
        //获取目标资源的RequestDispatcher(通常是JSP)。
        RequestDispatcher rd = getRequestDispatcher(requestToExpose, dispatcherPath);
        if (rd == null) {
   
   
            throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
                    "]: Check that the corresponding file exists within your web application archive!");
        }

        // If already included or response already committed, perform include, else forward.
        //如果已included或已提交响应,请执行include,否则forward。
        if (useInclude(requestToExpose, response)) {
   
   
            response.setContentType(getContentType());
            if (logger.isDebugEnabled()) {
   
   
                logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
            }
            rd.include(requestToExpose, response);
        }

        else {
   
   
            // Note: The forwarded resource is supposed to determine the content type itself.
            exposeForwardRequestAttributes(requestToExpose);
            if (logger.isDebugEnabled()) {
   
   
                logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
            }
            //执行forward
            rd.forward(requestToExpose, response);
        }
    }

最后总结一个流程图

在这里插入图片描述
文章结束,如果对你有所帮助,请给个好评,如果对你有所帮助,请给个好评

相关文章
|
7月前
|
Java 应用服务中间件 Spring
SpringMVC快速入门加登录流程分析
SpringMVC快速入门加登录流程分析
89 0
|
设计模式 前端开发 JavaScript
【SpringMVC】工作流程及入门案例
【SpringMVC】工作流程及入门案例
61 0
|
5天前
|
设计模式 前端开发 Java
步步深入SpringMvc DispatcherServlet源码掌握springmvc全流程原理
通过对 `DispatcherServlet`源码的深入剖析,我们了解了SpringMVC请求处理的全流程。`DispatcherServlet`作为前端控制器,负责请求的接收和分发,处理器映射和适配负责将请求分派到具体的处理器方法,视图解析器负责生成和渲染视图。理解这些核心组件及其交互原理,有助于开发者更好地使用和扩展SpringMVC框架。
22 4
|
4月前
|
前端开发 Java Spring
SpringMVC种通过追踪源码查看是哪种类型的视图渲染器(一般流程方法)
这篇文章通过示例代码展示了如何在Spring MVC中编写和注册拦截器,以及如何在拦截器的不同阶段添加业务逻辑。
SpringMVC种通过追踪源码查看是哪种类型的视图渲染器(一般流程方法)
|
7月前
|
JSON 前端开发 Java
SpringMVC概述、SpringMVC的工作流程、创建SpringMVC的项目
SpringMVC概述、SpringMVC的工作流程、创建SpringMVC的项目
49 2
|
7月前
|
前端开发 Java 定位技术
生活小事件(SpringMVC主要的组件及作用和执行流程)
Spring MVC 的主要组件包括 DispatcherServlet(核心,请求调度)、HandlerMapping(URL 映射到处理器)、HandlerAdapter(统一执行处理器)、Handler(处理业务逻辑,通常为 @Controller 类)、ViewResolver(视图解析)和 View(渲染输出)。通过这些组件的协作,Spring MVC 实现了从接收请求到返回响应的流程,类似于警察处理交通违规的协调过程。
|
JSON 数据格式 容器
SpringMVC运行流程分析之核心流程
SpringMVC运行流程分析之核心流程
36 0
|
7月前
|
前端开发 Java 应用服务中间件
SpringMvc拦截器和手写模拟SpringMvc工作流程源码详解
MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分。 M: Model,模型层,指工程中的JavaBean,作用是处理数据。 JavaBean分为两类: 1.实体类Bean:专门存储业务数据的,如Student User等 2.业务处理Bean:指Service或Dao对象,专门用于处理业务逻辑和数据访问。
|
7月前
|
JSON 前端开发 Java
SpringMVC概述、入门案例及工作流程
SpringMVC概述、入门案例及工作流程
36 0
|
开发框架 前端开发 Java
SpringMVC之入门:springmcx工作流程,springmvc的入门,静态资源处理器
SpringMVC之入门:springmcx工作流程,springmvc的入门,静态资源处理器
53 0