当前位置: 移动技术网 > IT编程>开发语言>Java > Spring MVC源码(二) ----- DispatcherServlet 请求处理流程 面试必问

Spring MVC源码(二) ----- DispatcherServlet 请求处理流程 面试必问

2019年07月16日  | 移动技术网IT编程  | 我要评论
前端控制器 前端控制器,即所谓的Front Controller,体现的是设计模式中的前端控制器模式。前端控制器处理所有从用户过来的请求。所有用户的请求都要通过前端控制器。SpringMVC框架和其他请求驱动的表示层框架一样,也是围绕一个将请求分发到相应控制器的核心Servlet来设计的。Dispa ...

前端控制器

前端控制器,即所谓的front controller,体现的是设计模式中的前端控制器模式。前端控制器处理所有从用户过来的请求。所有用户的请求都要通过前端控制器。springmvc框架和其他请求驱动的表示层框架一样,也是围绕一个将请求分发到相应控制器的核心servlet来设计的。dispatcherservlet和其他框架中的servlet不一样的地方在于,它和spring容器无缝整合在了一起,因此你可以在springmvc中使用spring容器所有的特性。

dispatcherservlet这个前端控制器,在springmvc中的作用,以官方文档中的配图来说明:

整个流程可以被大致描述为:一个http请求到达服务器,被dispatcherservlet接收。dispatcherservlet将请求委派给合适的处理器controller,此时处理控制权到达controller对象。controller内部完成请求的数据模型的创建和业务逻辑的处理,然后再将填充了数据后的模型即model和控制权一并交还给dispatcherservlet,委派dispatcherservlet来渲染响应。dispatcherservlet再将这些数据和适当的数据模版视图结合,向response输出响应。

dispatcherservlet

springmvc完成初始化流程之后,就进入servlet标准生命周期的第二个阶段,即“service”阶段。在“service”阶段中,每一次http请求到来,容器都会启动一个请求线程,通过service()方法,委派到doget()或者dopost()这些方法,完成http请求的处理。

在初始化流程中,springmvc巧妙的运用依赖注入读取参数,并最终建立一个与容器上下文相关联的spring子上下文。这个子上下文,就像struts2中xwork容器一样,为接下来的http处理流程中各种编程元素提供了容身之所。如果说将spring上下文关联到servlet容器中,是springmvc框架的第一个亮点,那么在请求转发流程中,springmvc对各种处理环节编程元素的抽象,就是另外一个独具匠心的亮点。

struts2采取的是一种完全和web容器隔离和解耦的事件机制。诸如action对象、result对象、interceptor对象,这些都是完全脱离servlet容器的编程元素。struts2将数据流和事件处理完全剥离开来,从http请求中读取数据后,下面的事件处理流程就只依赖于这些数据,而完全不知道有web环境的存在。

反观springmvc,无论handlermapping对象、handleradapter对象还是view对象,这些核心的接口所定义的方法中,httpservletrequest和httpservletresponse对象都是直接作为方法的参数出现的。这也就意味着,框架的设计者,直接将springmvc框架和容器绑定到了一起。或者说,整个springmvc框架,都是依托着servlet容器元素来设计的。下面就来看一下,源码中是如何体现这一点的。

请求转发的入口

就像任何一个注册在容器中的servlet一样,dispatcherservlet也是通过自己的service()方法来接收和转发http请求到具体的doget()或dopost()这些方法的。以一次典型的get请求为例,经过httpservlet基类中service()方法的委派,请求会被转发到doget()方法或者dopost()方法中。

protected void service(httpservletrequest req, httpservletresponse resp) throws servletexception, ioexception {
    string method = req.getmethod();
    long lastmodified;
    if (method.equals("get")) {
        lastmodified = this.getlastmodified(req);
        if (lastmodified == -1l) {
            this.doget(req, resp);
        } else {
            long ifmodifiedsince = req.getdateheader("if-modified-since");
            if (ifmodifiedsince < lastmodified) {
                this.maybesetlastmodified(resp, lastmodified);
                this.doget(req, resp);
            } else {
                resp.setstatus(304);
            }
        }
    } else if (method.equals("head")) {
        lastmodified = this.getlastmodified(req);
        this.maybesetlastmodified(resp, lastmodified);
        this.dohead(req, resp);
    } else if (method.equals("post")) {
        this.dopost(req, resp);
    } else if (method.equals("put")) {
        this.doput(req, resp);
    } else if (method.equals("delete")) {
        this.dodelete(req, resp);
    } else if (method.equals("options")) {
        this.dooptions(req, resp);
    } else if (method.equals("trace")) {
        this.dotrace(req, resp);
    } else {
        string errmsg = lstrings.getstring("http.method_not_implemented");
        object[] errargs = new object[]{method};
        errmsg = messageformat.format(errmsg, errargs);
        resp.senderror(501, errmsg);
    }

}

doget() 和 dopost() 方法,在dispatcherservlet的父类frameworkservlet类中被覆写。

protected final void doget(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception {
    this.processrequest(request, response);
}

protected final void dopost(httpservletrequest request, httpservletresponse response) throws servletexception, ioexception {
    this.processrequest(request, response);
}

可以看到,这里只是简单的转发到processrequest()这个方法。

protected final void processrequest(httpservletrequest request, httpservletresponse response)
        throws servletexception, ioexception {

    long starttime = system.currenttimemillis();
    throwable failurecause = null;

    // expose current localeresolver and request as localecontext.
    localecontext previouslocalecontext = localecontextholder.getlocalecontext();
    localecontextholder.setlocalecontext(buildlocalecontext(request), this.threadcontextinheritable);

    // expose current requestattributes to current thread.
    requestattributes previousrequestattributes = requestcontextholder.getrequestattributes();
    servletrequestattributes requestattributes = null;
    if (previousrequestattributes == null || previousrequestattributes.getclass().equals(servletrequestattributes.class)) {
        requestattributes = new servletrequestattributes(request);
        requestcontextholder.setrequestattributes(requestattributes, this.threadcontextinheritable);
    }

    if (logger.istraceenabled()) {
        logger.trace("bound request context to thread: " + request);
    }

    try {
        doservice(request, response);
    }
    finally {
        // clear request attributes and reset thread-bound context.
        localecontextholder.setlocalecontext(previouslocalecontext, this.threadcontextinheritable);
        if (requestattributes != null) {
            requestcontextholder.setrequestattributes(previousrequestattributes, this.threadcontextinheritable);
            requestattributes.requestcompleted();
        }
        if (this.publishevents) {
            // whether or not we succeeded, publish an event.
            long processingtime = system.currenttimemillis() - starttime;
            this.webapplicationcontext.publishevent(
                    new servletrequesthandledevent(this,
                            request.getrequesturi(), request.getremoteaddr(),
                            request.getmethod(), getservletconfig().getservletname(),
                            webutils.getsessionid(request), getusernameforrequest(request),
                            processingtime, failurecause));
        }
    }
}

可以看到,processrequest()方法只是做了一些线程安全的隔离,真正的请求处理,发生在doservice()方法中。点开frameworkservlet类中的doservice()方法。

protected abstract void doservice(httpservletrequest request, httpservletresponse response)
        throws exception;

又是一个抽象方法,这也是springmvc类设计中的惯用伎俩:父类抽象处理流程,子类给予具体的实现。真正的实现是在dispatcherservlet类中。

让我们接着看dispatcherservlet类中实现的doservice()方法。

@override
protected void doservice(httpservletrequest request, httpservletresponse response) throws exception {
    if (logger.isdebugenabled()) {
        string requesturi = urlpathhelper.getrequesturi(request);
        logger.debug("dispatcherservlet with name '" + getservletname() + "' processing " + request.getmethod() +
                " request for [" + requesturi + "]");
    }

    // keep a snapshot of the request attributes in case of an include,
    // to be able to restore the original attributes after the include.
    map<string, object> attributessnapshot = null;
    if (webutils.isincluderequest(request)) {
        logger.debug("taking snapshot of request attributes before include");
        attributessnapshot = new hashmap<string, object>();
        enumeration<?> attrnames = request.getattributenames();
        while (attrnames.hasmoreelements()) {
            string attrname = (string) attrnames.nextelement();
            if (this.cleanupafterinclude || attrname.startswith("org.springframework.web.servlet")) {
                attributessnapshot.put(attrname, request.getattribute(attrname));
            }
        }
    }

    // make framework objects available to handlers and view objects.
    request.setattribute(web_application_context_attribute, getwebapplicationcontext());
    request.setattribute(locale_resolver_attribute, this.localeresolver);
    request.setattribute(theme_resolver_attribute, this.themeresolver);
    request.setattribute(theme_source_attribute, getthemesource());

    flashmap inputflashmap = this.flashmapmanager.retrieveandupdate(request, response);
    if (inputflashmap != null) {
        request.setattribute(input_flash_map_attribute, collections.unmodifiablemap(inputflashmap));
    }
    request.setattribute(output_flash_map_attribute, new flashmap());
    request.setattribute(flash_map_manager_attribute, this.flashmapmanager);

    try {
        dodispatch(request, response);
    }
    finally {
        // restore the original attribute snapshot, in case of an include.
        if (attributessnapshot != null) {
            restoreattributesafterinclude(request, attributessnapshot);
        }
    }
}

几个requet.setattribute()方法的调用,将前面在初始化流程中实例化的对象设置到http请求的属性中,供下一步处理使用,其中有容器的上下文对象、本地化解析器等springmvc特有的编程元素。不同于struts2中的valuestack,springmvc的数据并没有从httpservletrequest对象中抽离出来再存进另外一个编程元素,这也跟springmvc的设计思想有关。因为从一开始,springmvc的设计者就认为,不应该将请求处理过程和web容器完全隔离

所以,你可以看到,真正发生请求转发的方法dodispatch()中,它的参数是httpservletrequest和httpservletresponse对象。这给我们传递的意思也很明确,从request中能获取到一切请求的数据,从response中,我们又可以往服务器端输出任何响应,http请求的处理,就应该围绕这两个对象来设计。我们不妨可以将springmvc这种设计方案,是从struts2的过度设计中吸取教训,而向servlet编程的一种回归和简化。

而对请求的处理交给dodispatcher方法

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

            // 决定当前请求的handler
            mappedhandler = gethandler(processedrequest);
            if (mappedhandler == null || mappedhandler.gethandler() == null) {
                nohandlerfound(processedrequest, response);
                return;
            }

            // 决定当前请求的handleradapter
            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 (logger.isdebugenabled()) {
                    logger.debug("last-modified value for [" + getrequesturi(request) + "] is: " + lastmodified);
                }
                if (new servletwebrequest(request, response).checknotmodified(lastmodified) && isget) {
                    return;
                }
            }

            // 拦截器的前置处理
            if (!mappedhandler.applyprehandle(processedrequest, response)) {
                return;
            }

            // handler实际执行请求
            mv = ha.handle(processedrequest, response, mappedhandler.gethandler());

            if (asyncmanager.isconcurrenthandlingstarted()) {
                return;
            }

            // 设置默认视图名
            applydefaultviewname(processedrequest, mv);
            // 拦截器后置处理
            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);
            }
        }
    }
}

先看dodispatcher方法执行的主要操作时序图

请求路由

gethandler方法就是从handlermapping中查询匹配当前request的handler。我们看到只要一匹配上 handler 就不再循环,直接返回

protected handlerexecutionchain gethandler(httpservletrequest request) throws exception {
    for (handlermapping hm : this.handlermappings) {
        handlerexecutionchain handler = hm.gethandler(request);
        if (handler != null) {
            return handler;
        }
    }
    return null;
}

handlermapping的gethandler方法在抽象基类abstracthandlermapping

public final handlerexecutionchain gethandler(httpservletrequest request) throws exception {
    // 由子类根据request获取handler
    object handler = gethandlerinternal(request);
    // 如果没匹配到,则获取默认handler
    if (handler == null) {
        handler = getdefaulthandler();
    }
    if (handler == null) {
        return null;
    }
    // 如果返回的handler为string,则使用spring容器实例化
    if (handler instanceof string) {
        string handlername = (string) handler;
        handler = getapplicationcontext().getbean(handlername);
    }

    // 查询匹配的拦截器,组装handler生成handlerexecutionchain
    handlerexecutionchain executionchain = gethandlerexecutionchain(handler, request);
    if (corsutils.iscorsrequest(request)) {
        corsconfiguration globalconfig = this.corsconfigsource.getcorsconfiguration(request);
        corsconfiguration handlerconfig = getcorsconfiguration(handler, request);
        corsconfiguration config = (globalconfig != null ? globalconfig.combine(handlerconfig) : handlerconfig);
        executionchain = getcorshandlerexecutionchain(request, executionchain, config);
    }
    return executionchain;
}

最终返回的handler是由拦截器链和handler共同组成的,而具体匹配handler的方法是交给子类来完成的。上一章组件初始化中提到生产环境下使用的是requestmappinghandlermapping,gethandlerinternal方法的实现在它的基类abstracthandlermethodmapping。

protected handlermethod gethandlerinternal(httpservletrequest request) throws exception {
    // 从request获取匹配url
    string lookuppath = geturlpathhelper().getlookuppathforrequest(request);
    if (logger.isdebugenabled()) {
        logger.debug("looking up handler method for path " + lookuppath);
    }
    this.mappingregistry.acquirereadlock();
    try {
        // 查询匹配的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);
    }
    finally {
        this.mappingregistry.releasereadlock();
    }
}

可以看到返回的handler的类型为handlermethod,它对应于controller中的方法。上一章也提过,在abstracthandlermethodmapping中有一个mappingregistry,统一管理url和controller方法的映射关系,lookuphandlermethod就是对mappingregistry的操作。

protected handlermethod lookuphandlermethod(string lookuppath, httpservletrequest request) throws exception {
    list<match> matches = new arraylist<match>();
    // 从mappingregistry获取匹配到的requestmappinginfo
    list<t> directpathmatches = this.mappingregistry.getmappingsbyurl(lookuppath);
    if (directpathmatches != null) {
        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));
        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) {
            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();
                throw new illegalstateexception("ambiguous handler methods mapped for http path '" +
                        request.getrequesturl() + "': {" + m1 + ", " + m2 + "}");
            }
        }
        handlematch(bestmatch.mapping, lookuppath, request);
        return bestmatch.handlermethod;
    }
    else {
        // 无匹配项处理
        return handlenomatch(this.mappingregistry.getmappings().keyset(), lookuppath, request);
    }
}

通过mappingregistry匹配返回requestmappinginfo,对应于每个有@requestmapping注解解析后的method。

我们来看看,handlerexecutionchain类的代码。

package org.springframework.web.servlet;

import java.util.arraylist;
import java.util.arrays;
import java.util.list;

import org.springframework.util.collectionutils;

public class handlerexecutionchain {

    private final object handler;

    private handlerinterceptor[] interceptors;

    private list<handlerinterceptor> interceptorlist;

    public handlerexecutionchain(object handler) {
        this(handler, null);
    }

    public handlerexecutionchain(object handler, handlerinterceptor[] interceptors) {
        if (handler instanceof handlerexecutionchain) {
            handlerexecutionchain originalchain = (handlerexecutionchain) handler;
            this.handler = originalchain.gethandler();
            this.interceptorlist = new arraylist<handlerinterceptor>();
            collectionutils.mergearrayintocollection(originalchain.getinterceptors(), this.interceptorlist);
            collectionutils.mergearrayintocollection(interceptors, this.interceptorlist);
        }
        else {
            this.handler = handler;
            this.interceptors = interceptors;
        }
    }

    public object gethandler() {
        return this.handler;
    }

    public void addinterceptor(handlerinterceptor interceptor) {
        initinterceptorlist();
        this.interceptorlist.add(interceptor);
    }

    public void addinterceptors(handlerinterceptor[] interceptors) {
        if (interceptors != null) {
            initinterceptorlist();
            this.interceptorlist.addall(arrays.aslist(interceptors));
        }
    }

    private void initinterceptorlist() {
        if (this.interceptorlist == null) {
            this.interceptorlist = new arraylist<handlerinterceptor>();
        }
        if (this.interceptors != null) {
            this.interceptorlist.addall(arrays.aslist(this.interceptors));
            this.interceptors = null;
        }
    }

    public handlerinterceptor[] getinterceptors() {
        if (this.interceptors == null && this.interceptorlist != null) {
            this.interceptors = this.interceptorlist.toarray(new handlerinterceptor[this.interceptorlist.size()]);
        }
        return this.interceptors;
    }

}

一个拦截器列表,一个执行对象,这个类的内容十分的简单,它蕴含的设计思想,却十分的丰富。

1.拦截器组成的列表,在执行对象被调用的前后,会依次执行。这里可以看成是一个的aop环绕通知,拦截器可以对处理对象随心所欲的进行处理和增强。这里明显是吸收了struts2中拦截器的设计思想。这种aop环绕式的扩展点设计,也几乎成为所有框架必备的内容。

2.实际的处理对象,即handler对象,是由object对象来引用的。

private final object handler;

当我们拿到handlerexecutionchain,就完成了request到controller的路由操作。

适配器匹配

有了handler后,需要合适的handleradapter对其进行操作,因而就要根据handler进行匹配。

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

handleradapter接口中定义了supports方法,用于检测是否支持handler。生产环境使用的requestmappinghandleradapter在其基类abstracthandlermethodadapter中实现了supports方法。

public final boolean supports(object handler) {
    return (handler instanceof handlermethod && supportsinternal((handlermethod) handler));
}

supportsinternal方法在requestmappinghandleradapter的实现里默认返回true。因而requestmappinghandleradapter就是用来支持类型为handlermethod的handler的处理的。

拦截器处理

在springmvc中的拦截器接口handlerinterceptor中定义了三个方法

public interface handlerinterceptor {

    // 在handler找到后,执行前拦截
    boolean prehandle(httpservletrequest request, httpservletresponse response, object handler)
            throws exception;

    // 在handler执行后,视图渲染前拦截
    void posthandle(
            httpservletrequest request, httpservletresponse response, object handler, modelandview modelandview)
            throws exception;

    // 请求处理完成,视图渲染后执行资源清理等
    void aftercompletion(
            httpservletrequest request, httpservletresponse response, object handler, exception ex)
            throws exception;

}

可以很清晰地对应到dodispatcher方法中。需要注意的有几点

  1. 前置处理prehandle,返回值为boolean。如果返回true,则执行下一个,如果返回false,则认为当前拦截器完成了请求,dispatcherservlet会直接返回,在返回前会调用所有拦截器的aftercompletion方法,完成清理工作。
  2. aftercompletion方法在遇到任何情况时都需要被执行,无论是成功返回还是抛出异常。

执行请求

handleradapter的handle方法完成请求的真正执行。在abstracthandlermethodadapter中由handleinternal执行。

protected modelandview handleinternal(httpservletrequest request,
        httpservletresponse response, handlermethod handlermethod) throws exception {

    modelandview mav;
    checkrequest(request);


    // 执行handlermethod
    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中,handlermethod被封装servletinvocablehandlermethod,包裹上方法执行需要的信息。

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

        // 封装handlermethod
        servletinvocablehandlermethod invocablemethod = createinvocablehandlermethod(handlermethod);
        invocablemethod.sethandlermethodargumentresolvers(this.argumentresolvers);
        invocablemethod.sethandlermethodreturnvaluehandlers(this.returnvaluehandlers);
        invocablemethod.setdatabinderfactory(binderfactory);
        invocablemethod.setparameternamediscoverer(this.parameternamediscoverer);

        modelandviewcontainer mavcontainer = new modelandviewcontainer();
        mavcontainer.addallattributes(requestcontextutils.getinputflashmap(request));
        modelfactory.initmodel(webrequest, mavcontainer, invocablemethod);
        mavcontainer.setignoredefaultmodelonredirect(this.ignoredefaultmodelonredirect);

        // 异步请求处理
        asyncwebrequest asyncwebrequest = webasyncutils.createasyncwebrequest(request, response);
        asyncwebrequest.settimeout(this.asyncrequesttimeout);

        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 + "]");
            }
            invocablemethod = invocablemethod.wrapconcurrentresult(result);
        }

        // 执行处理
        invocablemethod.invokeandhandle(webrequest, mavcontainer);
        if (asyncmanager.isconcurrenthandlingstarted()) {
            return null;
        }

        // 封装数据和视图
        return getmodelandview(mavcontainer, modelfactory, webrequest);
    }
    finally {
        webrequest.requestcompleted();
    }
}

再到servletinvocablehandlermethod的invokeandhandle方法

public void invokeandhandle(servletwebrequest webrequest, modelandviewcontainer mavcontainer,
        object... providedargs) throws exception {

    // 执行request
    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);
    try {
        // 对返回值进行处理
        this.returnvaluehandlers.handlereturnvalue(
                returnvalue, getreturnvaluetype(returnvalue), mavcontainer, webrequest);
    }
    catch (exception ex) {
        if (logger.istraceenabled()) {
            logger.trace(getreturnvaluehandlingerrormessage("error handling return value", returnvalue), ex);
        }
        throw ex;
    }
}

public object invokeforrequest(nativewebrequest request, modelandviewcontainer mavcontainer,
        object... providedargs) throws exception {

    // 执行方法参数
    object[] args = getmethodargumentvalues(request, mavcontainer, providedargs);
    if (logger.istraceenabled()) {
        logger.trace("invoking '" + classutils.getqualifiedmethodname(getmethod(), getbeantype()) +
                "' with arguments " + arrays.tostring(args));
    }
    
    object returnvalue = doinvoke(args);
    if (logger.istraceenabled()) {
        logger.trace("method [" + classutils.getqualifiedmethodname(getmethod(), getbeantype()) +
                "] returned [" + returnvalue + "]");
    }
    return returnvalue;
}

protected object doinvoke(object... args) throws exception {
    reflectionutils.makeaccessible(getbridgedmethod());
    return getbridgedmethod().invoke(getbean(), args);
}

需要说明的一点是方法执行完成的返回值通过返回值处理器handlermethodreturnvaluehandler进行处理。在requestmappinghandleradapter的初始化中,内置了众多的handlermethodreturnvaluehandler来处理多种类型的返回值。

在完成请求执行后,dodispatcher方法中做了一个默认view的设置。

applydefaultviewname(processedrequest, mv);

private void applydefaultviewname(httpservletrequest request, modelandview mv) throws exception {
    if (mv != null && !mv.hasview()) {
        mv.setviewname(getdefaultviewname(request));
    }
}

而这个getdefaultviewname是通过requesttoviewnametranslator的实现类来解析的

protected string getdefaultviewname(httpservletrequest request) throws exception {
    return this.viewnametranslator.getviewname(request);
}

默认实现defaultrequesttoviewnametranslator,根据配置的一些通用url进行匹配

public string getviewname(httpservletrequest request) {
    string lookuppath = this.urlpathhelper.getlookuppathforrequest(request);
    return (this.prefix + transformpath(lookuppath) + this.suffix);
}

视图渲染

当请求完成后,返回的modelandview需要渲染到浏览器进行显示。dodispatcher方法中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 {
            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;
    }

    // 完成后执行拦截器的aftercompletion
    if (mappedhandler != null) {
        mappedhandler.triggeraftercompletion(request, response, null);
    }
}

render方法执行渲染,最终由view实现类执行

view.render(mv.getmodelinternal(), request, response);

抽象类abstractview执行对数据进行组装,输出操作交由子类完成

public void render(map<string, ?> model, httpservletrequest request, httpservletresponse response) throws exception {
    if (logger.istraceenabled()) {
        logger.trace("rendering view with name '" + this.beanname + "' with model " + model +
            " and static attributes " + this.staticattributes);
    }

    // 组装数据
    map<string, object> mergedmodel = createmergedoutputmodel(model, request, response);
    prepareresponse(request, response);
    // 渲染输出
    rendermergedoutputmodel(mergedmodel, getrequesttoexpose(request), response);
}

以通用的internalresourceview举例

protected void rendermergedoutputmodel(
        map<string, object> model, httpservletrequest request, httpservletresponse response) throws exception {

    // expose the model object as request attributes.
    exposemodelasrequestattributes(model, request);

    // expose helpers as request attributes, if any.
    exposehelpers(request);

    // determine the path for the request dispatcher.
    string dispatcherpath = prepareforrendering(request, response);

    // obtain a requestdispatcher for the target resource (typically a jsp).
    requestdispatcher rd = getrequestdispatcher(request, 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.
    if (useinclude(request, response)) {
        response.setcontenttype(getcontenttype());
        if (logger.isdebugenabled()) {
            logger.debug("including resource [" + geturl() + "] in internalresourceview '" + getbeanname() + "'");
        }
        rd.include(request, response);
    }

    else {
        // note: the forwarded resource is supposed to determine the content type itself.
        if (logger.isdebugenabled()) {
            logger.debug("forwarding to resource [" + geturl() + "] in internalresourceview '" + getbeanname() + "'");
        }
        rd.forward(request, response);
    }
}

最终由java servlet的requestdispatcher完成输出。其实就是做了一个跳转

本章中以请求的正向主流程解析了dispatcherservlet及相关类完成此过程的源码,其主要过程则是handlerexecutionchain,handlermapping,handleradapter,view等组件的交互过程,贴两张网上的核心原理图,希望对大家理解springmvc的原理有帮助。

 

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网