Spring MVC源码(二) ----- DispatcherServlet 请求处理流程 面试必问
前端控制器
前端控制器,即所谓的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方法中。需要注意的有几点
- 前置处理prehandle,返回值为boolean。如果返回true,则执行下一个,如果返回false,则认为当前拦截器完成了请求,dispatcherservlet会直接返回,在返回前会调用所有拦截器的aftercompletion方法,完成清理工作。
- 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的原理有帮助。