SpringMVC源码分析(3)DispatcherServlet的请求处理流程
<SpringMVC源码分析(1)标签解析>:介绍了解析过程中,初始化若干组件。 <SpringMVC源码分析(2)DispatcherServlet的初始化>:初始化DispatcherServlet的多个组件。 本文继续分析DispatcherServlet解析请求的过程。 概览 ①:DispatcherServlet是springmvc中的前端控制器(front controller),负责接收request并将request转发给对应的处理组件. ②:HanlerMapping是springmvc中完成url到controller映射的组件.DispatcherServlet接收request,然后从HandlerMapping查找处理request的controller. ③:Cntroller处理request,并返回ModelAndView对象,Controller是springmvc中负责处理request的组件(类似于struts2中的Action),ModelAndView是封装结果视图的组件. ④ ⑤ ⑥:视图解析器解析ModelAndView对象并返回对应的视图给客户端. 要点 维护url和controller的映射这部分工作由DefaultAnnotationHandlerMapping.setApplicationContext的父类org.springframework.web.servlet.handler.AbstractDetectingUrlHandlerMapping.initApplicationContext实现。具体方法为detectHandlers protectedvoiddetectHandlers()throwsBeansException{ if(logger.isDebugEnabled()){ logger.debug("LookingforURLmappingsinapplicationcontext:"+getApplicationContext()); } String[]beanNames=(this.detectHandlersInAncestorContexts? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(),Object.class): getApplicationContext().getBeanNamesForType(Object.class)); //TakeanybeannamethatwecandetermineURLsfor. for(StringbeanName:beanNames){ String[]urls=determineUrlsForHandler(beanName); if(!ObjectUtils.isEmpty(urls)){ //URLpathsfound:Let'sconsideritahandler. registerHandler(urls,beanName); } else{ if(logger.isDebugEnabled()){ logger.debug("Rejectedbeanname'"+beanName+"':noURLpathsidentified"); } } } } 2.准确定位处理请求的具体方法(在AnnotationMethodHandlerAdapter中实现) protectedModelAndViewinvokeHandlerMethod(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler) throwsException{ ServletHandlerMethodResolvermethodResolver=getMethodResolver(handler); MethodhandlerMethod=methodResolver.resolveHandlerMethod(request);//具体实现方法的匹配 ServletHandlerMethodInvokermethodInvoker=newServletHandlerMethodInvoker(methodResolver); ServletWebRequestwebRequest=newServletWebRequest(request,response); ExtendedModelMapimplicitModel=newBindingAwareModelMap(); Objectresult=methodInvoker.invokeHandlerMethod(handlerMethod,handler,webRequest,implicitModel); ModelAndViewmav= methodInvoker.getModelAndView(handlerMethod,handler.getClass(),result,implicitModel,webRequest); methodInvoker.updateModelAttributes(handler,(mav!=null?mav.getModel():null),implicitModel,webRequest); returnmav; } 1.请求入口 @Override protectedfinalvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse) throwsServletException,IOException{ proce***equest(request,response); } /** *DelegatePOSTrequeststo{@link#proce***equest}. *@see#doService */ @Override protectedfinalvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse) throwsServletException,IOException{ proce***equest(request,response); } protectedfinalvoidproce***equest(HttpServletRequestrequest,HttpServletResponseresponse) throwsServletException,IOException{ longstartTime=System.currentTimeMillis(); ThrowablefailureCause=null; //ExposecurrentLocaleResolverandrequestasLocaleContext. LocaleContextpreviousLocaleContext=LocaleContextHolder.getLocaleContext(); LocaleContextHolder.setLocaleContext(buildLocaleContext(request),this.threadContextInheritable); //ExposecurrentRequestAttributestocurrentthread. RequestAttributespreviousRequestAttributes=RequestContextHolder.getRequestAttributes(); ServletRequestAttributesrequestAttributes=null; if(previousRequestAttributes==null||previousRequestAttributes.getClass().equals(ServletRequestAttributes.class)){ requestAttributes=newServletRequestAttributes(request); RequestContextHolder.setRequestAttributes(requestAttributes,this.threadContextInheritable); } if(logger.isTraceEnabled()){ logger.trace("Boundrequestcontexttothread:"+request); } try{ doService(request,response); } catch(ServletExceptionex){ failureCause=ex; throwex; } catch(IOExceptionex){ failureCause=ex; throwex; } catch(Throwableex){ failureCause=ex; thrownewNestedServletException("Requestprocessingfailed",ex); } finally{ //Clearrequestattributesandresetthread-boundcontext. LocaleContextHolder.setLocaleContext(previousLocaleContext,this.threadContextInheritable); if(requestAttributes!=null){ RequestContextHolder.setRequestAttributes(previousRequestAttributes,this.threadContextInheritable); requestAttributes.requestCompleted(); } if(logger.isTraceEnabled()){ logger.trace("Clearedthread-boundrequestcontext:"+request); } if(failureCause!=null){ this.logger.debug("Couldnotcompleterequest",failureCause); } else{ this.logger.debug("Successfullycompletedrequest"); } if(this.publishEvents){ //Whetherornotwesucceeded,publishanevent. longprocessingTime=System.currentTimeMillis()-startTime; this.webApplicationContext.publishEvent( newServletRequestHandledEvent(this, request.getRequestURI(),request.getRemoteAddr(), request.getMethod(),getServletConfig().getServletName(), WebUtils.getSessionId(request),getUsernameForRequest(request), processingTime,failureCause)); } } } proce***equest方法主要做4项工作。 得到当前线程的LocaleContext和RequestAttributes,创建新的LocaleContext和RequestAttributes并重新绑定到当前线程。 调用子类实现的doService() 重置当前线程的LocaleContext和RequestAttributes 执行成功后,发布ServletRequestHandledEvent事件。 2.DispatcherServlet自定义的doService方法 protectedvoiddoService(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{ if(logger.isDebugEnabled()){ StringrequestUri=urlPathHelper.getRequestUri(request); logger.debug("DispatcherServletwithname'"+getServletName()+"'processing"+request.getMethod()+ "requestfor["+requestUri+"]"); } //Keepasnapshotoftherequestattributesincaseofaninclude, //tobeabletorestoretheoriginalattributesaftertheinclude. Map<String,Object>attributesSnapshot=null; if(WebUtils.isIncludeRequest(request)){ logger.debug("Takingsnapshotofrequestattributesbeforeinclude"); attributesSnapshot=newHashMap<String,Object>(); EnumerationattrNames=request.getAttributeNames(); while(attrNames.hasMoreElements()){ StringattrName=(String)attrNames.nextElement(); if(this.cleanupAfterInclude||attrName.startsWith("org.springframework.web.servlet")){ attributesSnapshot.put(attrName,request.getAttribute(attrName)); } } } //Makeframeworkobjectsavailabletohandlersandviewobjects. 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()); try{ doDispatch(request,response); } finally{ //Restoretheoriginalattributesnapshot,incaseofaninclude. if(attributesSnapshot!=null){ restoreAttributesAfterInclude(request,attributesSnapshot); } } } 主要做两部分工作 如果是include请求,先保存一份request域数据的快照,doDispatch执行过后,将会用快照数据恢复。 调用doDispatch方法,完成请求转发。 3.doDispatch方法 protectedvoiddoDispatch(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{ HttpServletRequestprocessedRequest=request; HandlerExecutionChainmappedHandler=null; intinterceptorIndex=-1; try{ ModelAndViewmv; booleanerrorView=false; try{ //1.检查是否是文件上传的请求 processedRequest=checkMultipart(request); //Determinehandlerforthecurrentrequest. //2.取得处理当前请求的controller,这里也称为hanlder,处理器,第一个步骤的意义就在这里体现了. //这里并不是直接返回controller,而是返回的HandlerExecutionChain请求处理器链对象,该对象封装了handler和interceptors. mappedHandler=getHandler(processedRequest,false); if(mappedHandler==null||mappedHandler.getHandler()==null){ noHandlerFound(processedRequest,response); return; } //Determinehandleradapterforthecurrentrequest. //3.获取处理request的处理器适配器handleradapter HandlerAdapterha=getHandlerAdapter(mappedHandler.getHandler()); //Processlast-modifiedheader,ifsupportedbythehandler. Stringmethod=request.getMethod(); booleanisGet="GET".equals(method); if(isGet||"HEAD".equals(method)){ longlastModified=ha.getLastModified(request,mappedHandler.getHandler()); if(logger.isDebugEnabled()){ StringrequestUri=urlPathHelper.getRequestUri(request); logger.debug("Last-Modifiedvaluefor["+requestUri+"]is:"+lastModified); } if(newServletWebRequest(request,response).checkNotModified(lastModified)&&isGet){ return; } } //ApplypreHandlemethodsofregisteredinterceptors. //4.拦截器的预处理方法 HandlerInterceptor[]interceptors=mappedHandler.getInterceptors(); if(interceptors!=null){ for(inti=0;i<interceptors.length;i++){ HandlerInterceptorinterceptor=interceptors[i]; if(!interceptor.preHandle(processedRequest,response,mappedHandler.getHandler())){ triggerAfterCompletion(mappedHandler,interceptorIndex,processedRequest,response,null); return; } interceptorIndex=i; } } //Actuallyinvokethehandler. //5.实际的处理器处理请求,返回结果视图对象 mv=ha.handle(processedRequest,response,mappedHandler.getHandler()); //Doweneedviewnametranslation? if(mv!=null&&!mv.hasView()){ mv.setViewName(getDefaultViewName(request)); } //ApplypostHandlemethodsofregisteredinterceptors. //6.拦截器的后处理方法 if(interceptors!=null){ for(inti=interceptors.length-1;i>=0;i--){ HandlerInterceptorinterceptor=interceptors[i]; interceptor.postHandle(processedRequest,response,mappedHandler.getHandler(),mv); } } } catch(ModelAndViewDefiningExceptionex){ logger.debug("ModelAndViewDefiningExceptionencountered",ex); mv=ex.getModelAndView(); } catch(Exceptionex){ Objecthandler=(mappedHandler!=null?mappedHandler.getHandler():null); mv=processHandlerException(processedRequest,response,handler,ex); errorView=(mv!=null); } //Didthehandlerreturnaviewtorender? if(mv!=null&&!mv.wasCleared()){ render(mv,processedRequest,response); if(errorView){ WebUtils.clearErrorRequestAttributes(request); } } else{ if(logger.isDebugEnabled()){ logger.debug("NullModelAndViewreturnedtoDispatcherServletwithname'"+getServletName()+ "':assumingHandlerAdaptercompletedrequesthandling"); } } //Triggerafter-completionforsuccessfuloutcome. triggerAfterCompletion(mappedHandler,interceptorIndex,processedRequest,response,null); } catch(Exceptionex){ //Triggerafter-completionforthrownexception. triggerAfterCompletion(mappedHandler,interceptorIndex,processedRequest,response,ex); throwex; } catch(Errorerr){ ServletExceptionex=newNestedServletException("Handlerprocessingfailed",err); //Triggerafter-completionforthrownexception. triggerAfterCompletion(mappedHandler,interceptorIndex,processedRequest,response,ex); throwex; } finally{ //Cleanupanyresourcesusedbyamultipartrequest. if(processedRequest!=request){ cleanupMultipart(processedRequest); } } } 很明显这儿是SpringMVC核心。 1.根据请求的路径找到HandlerMethod(带有Method反射属性,也就是对应Controller中的方法)(DispatcherServlet.getHandler完成) 2.匹配路径对应的拦截器(DispatcherServlet.getHandler完成) 3.获得HandlerExecutionChain对象(DispatcherServlet.getHandler完成) 4.通过HandlerAdapter对象进行处理得到ModelAndView对象(HandlerAdapter.handle) 5.调用HandlerInterceptor.preHandle 6.调用HandlerInterceptor.postHandle 7. 渲染 4.总结 简单粗暴的总结下 step1-6: 获取controller step5-15 :调用controller方法 step17-20:渲染view 其他:aop方式处理拦截统一处理。