SpringMVC源码学习笔记之请求处理流程

得意时要看淡,失意时要看开。不论得意失意,切莫大意;不论成功失败,切莫止步。志得意满时,需要的是淡然,给自己留一条退路;失意落魄时,需要的是泰然,给自己觅一条出路SpringMVC源码学习笔记之请求处理流程,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

一、常用组件

1、DispatcherServlet

前端控制器,SpringMVC里最核心的组件,是整个SpringMVC请求流程的中心,主要流程都是由DispatcherServlet来调用其他组件,而且看名字就知道,它是一个Servlet

2、HandlerMapping

处理器映射器,根据请求来查找对应的处理器Handler,其实就是Controller

3、Handler(Controller)

处理器,由软件工程师开发,其实就是Controller,用于具体处理用户的请求

4、HandlerAdapter

处理器适配器,因为SpringMVC中的Handler可以是任意的形式,只要能处理请求就可以了,但是Servlet需要的处理方法的结构却是固定的,都是以request和response为参数的方法,所以如何让固定的Servlet处理方法调用灵活的Handler来进行处理呢?这就要用到HandlerAdapter了

注:网上看到一个很有意思的形容:

Handler是用来干活的工具

HandlerMapping用来根据需要干的活找到对应的工具

HandlerAdapter是使用工具干活的人

5、ViewResolver

视图解析器,根据视图名称解析成View类型的视图,View是用来渲染页面的,也就是将程序返回的数据填入模板里,生成html或者其他类型的文件,具体使用哪个模板,用什么规则填入数据就是ViewResolver要做的事,然后具体的渲染交给View去做

二、流程图

SpringMVC源码学习笔记之请求处理流程

流程梳理:

1、用户通过浏览器发送请求到前端控制器(DispatcherServlet)

2、前端控制器(DispatcherServlet)将用户请求交给处理器映射器(HandlerMapping)

3-4、处理器映射器(HandlerMapping)找到负责这个请求的处理器(Handler)并和拦截器链一起封装成处理器执行链(HandlerExecutionChain)交给前端控制器(DispatcherServlet)

5、前端控制器(DispatcherServlet)会根据处理器(Handler)找到对应的处理器适配器(HandlerAdaptor)

6-9、处理器适配器(HandlerAdaptor) 会去执行具体的Controller,Controller将处理结果及要跳转的视图封装到ModelAndView返回给处理器适配器(HandlerAdaptor),并在执行Controller前后调用拦截器链

10、处理器适配器(HandlerAdaptor) 将ModelAndView返回给前端控制器(DispatcherServlet)

11、前端控制器(DispatcherServlet)将ModelAndView交给视图解析器(ViewResolver)

12、视图解析器(ViewResolver)将ModelAndView解析为具体的视图(View)返回给前端控制器(DispatcherServlet)

13、前端控制器(DispatcherServlet)调用视图对象,让其自己 (View) 进行渲染(将模型数据填充至视图中) ,形成响应 (HttpResponse)

14、前端控制器(DispatcherServlet)将响应 (HttpResponse) 返回给浏览器

三、源码解读

1、doDispatch

首先我们要先知道SpringMVC的Servlet分为三层HttpServletBean、FrameworkServlet和DispatcherServlet,我们知道Servlet的入口是service方法,FrameworkServlet重写了service方法,我们往里跟代码,最终会来到DispatcherServlet的核心方法doDispatch

//DispatcherServlet
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 {
            //检查是否是文件上传的请求
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            //获取处理器,注意这里的mappedHandler里包含了handler和拦截器链
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                //找不到处理器,报404
                noHandlerFound(processedRequest, response);
                return;
            }

            //根据处理器里的handler获取对应的适配器
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            //处理last-modified请求头
            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;
                }
            }

            //在处理请求前先执行拦截器的preHandle方法,这个方法会返回一个boolean类型的值
            //如果是true,就交给后面的拦截器继续处理,
            //如果是false就表示处理完了,顺便也把response搞定
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            //用适配器处理请求,返回ModelAndView
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

            //判断是否需要viewNameTranslator从request里获取view的名字
            applyDefaultViewName(processedRequest, mv);
            //执行拦截器的PostHandle方法
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        catch (Throwable err) {
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        //页面渲染,调用拦截器的afterCompletion方法等
        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()) {
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        }
        else {
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
}

2、getHandler

//获取处理器,注意这里的mappedHandler里包含了handler和拦截器链
mappedHandler = getHandler(processedRequest);

首先我们看下18行的getHandler方法,对应流程图中的2-4步

//DispatcherServlet
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            //逐个使用HandlerMapping去获取Handler,如果获取到了就返回,没获取到就换下一个
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

这里的handlerMappings是个List集合,HandlerMapper有很多实现类,最重要的就是RequestMappingHandlerMapping和BeanNameUrlHandlerMapping,我们记住这两个类,继续看第7行getHandler,进入到AbstractHandlerMapping类里

//AbstractHandlerMapping
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    //获取handler
    Object handler = getHandlerInternal(request);
    if (handler == null) {
        handler = getDefaultHandler();
    }
    if (handler == null) {
        return null;
    }
    
    if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = obtainApplicationContext().getBean(handlerName);
    }

    //找到匹配的拦截器和handler一起封装成一个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 (CorsUtils.isCorsRequest(request)) {
        CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }

    return executionChain;
}

核心逻辑是第6行的getHandlerInternal,getHandlerInternal是个模板方法,最终会调用子类实现,这里有两个重要的实现类,分别是AbstractHandlerMethodMapping和AbstractUrlHandlerMapping,上面我们提到HandlerMapper有两个非常主要的实现类:RequestMappingHandlerMapping和BeanNameUrlHandlerMapping,我们看看这两个类的类图

SpringMVC源码学习笔记之请求处理流程

SpringMVC源码学习笔记之请求处理流程

我们发现RequestMappingHandlerMapping是AbstractHandlerMethodMapping的子类,而BeanNameUrlHandlerMapping是AbstractUrlHandlerMapping的子类

  • RequestMappingHandlerMapping:主要用来存储RequestMapping注解相关的控制器和url的映射关系

  • BeanNameUrlHandlerMapping: 主要用来处理Bean name直接以 / 开头的控制器和url的映射关系。

我们最常用的其实还是RequestMappingHandlerMapping,所以我们进入AbstractHandlerMethodMapping的getHandlerInternal方法,继续看

//AbstractHandlerMethodMapping
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    //获取requestMapping地址
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    this.mappingRegistry.acquireReadLock();
    try {
        //查找Handler
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        this.mappingRegistry.releaseReadLock();
    }
}

第9行核心方法进去

//AbstractHandlerMethodMapping
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<>();
    //从mappingRegistry中获取命中的方法
    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        //寻找合适的mapping,根据属性去精确查找,最终防到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()) {
        Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
        matches.sort(comparator);
        Match bestMatch = matches.get(0);
        if (matches.size() > 1) {
            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);
    }
}

具体看下第9行addMatchingMappings

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

这里有个mappingRegistry很重要,mappingRegistry.getMappings,返回的是HandlerMethod的map,这一步相当于把匹配到的HandlerMethod封装到Match对象中,最后加到matches集合里,最后排序,取出第一个匹配的Handler返回

我们回到getHandler方法

//AbstractHandlerMapping
@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    //获取handler
    Object handler = getHandlerInternal(request);
    if (handler == null) {
        handler = getDefaultHandler();
    }
    if (handler == null) {
        return null;
    }
    
    if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = obtainApplicationContext().getBean(handlerName);
    }

    //找到匹配的拦截器和handler一起封装成一个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 (CorsUtils.isCorsRequest(request)) {
        CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }

    return executionChain;
}

第6行返回的就是刚才的HandlerMethod对象,然后调用getHandlerExecutionChain方法,将HandlerMethod和拦截器链封装成HandlerExecutionChain对象返回

3、HandlerAdapter.handle

//用适配器处理请求,返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

下面看第47行handle方法,点击进到实现类AbstractHandlerMethodAdapter的handle方法中

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

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

继续点击handleInternal进入子类RequestMappingHandlerAdapter的handleInternal方法中

//RequestMappingHandlerAdapter
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

    ModelAndView mav;
    //检查是否支持当前request的请求方式和session
    checkRequest(request);

    //如果需要,在同步块中执行invokeHandlerMethod。
    if (this.synchronizeOnSession) {
        HttpSession session = request.getSession(false);
        if (session != null) {
            Object mutex = WebUtils.getSessionMutex(session);
            synchronized (mutex) {
                mav = invokeHandlerMethod(request, response, handlerMethod);
            }
        }
        else {
            //无HttpSession可用->无需互斥
            mav = invokeHandlerMethod(request, response, handlerMethod);
        }
    }
    else {
        //不需要同步会话
        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方法,点击进去

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

    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        //省略...

        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }

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

继续点击10行invokeAndHandle进到类ServletInvocableHandlerMethod中

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

点击5行invokeForRequest进入其父类InvocableHandlerMethod中

@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));
    }
	//执行具体业务
    return doInvoke(args);
}

其中doInvoke方法最终会通过反射调用到Controller上的方法,我们具体看看getMethodArgumentValues方法

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {

    //获取Controller对应的方法所有参数,该部分在程序启动时就已经解析好了
    if (ObjectUtils.isEmpty(getMethodParameters())) {
        return EMPTY_ARGS;
    }
    MethodParameter[] parameters = getMethodParameters();
    Object[] args = new Object[parameters.length];
    //遍历所有参数,进行赋值
    for (int i = 0; i < parameters.length; i++) {
        MethodParameter parameter = parameters[i];
        parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
        args[i] = findProvidedArgument(parameter, providedArgs);
        if (args[i] != null) {
            continue;
        }
        if (!this.resolvers.supportsParameter(parameter)) {
            throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
        }
        try {
            //解析参数并赋值,这里会根据参数找到对应的解析器进行解析
            args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
        }
        catch (Exception ex) {
            if (logger.isDebugEnabled()) {
                String error = ex.getMessage();
                if (error != null && !error.contains(parameter.getExecutable().toGenericString())) {
                    logger.debug(formatArgumentError(parameter, error));
                }
            }
            throw ex;
        }
    }
    return args;
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/154504.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!