SpringMVC源码分析(3)DispatcherServlet的请求处理流程


<springmvc源码分析(2)dispatcherservlet的初始化>初始化DispatcherServlet的多个组件。

本文继续分析DispatcherServlet解析请求的过程。

概览

231546366285136.jpg

  ①: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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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中实现)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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.请求入口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
@Override
protectedfinalvoiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,IOException{
 
processRequest(request,response);
}
 
/**
*DelegatePOSTrequeststo{@link#processRequest}.
*@see#doService
*/
@Override
protectedfinalvoiddoPost(HttpServletRequestrequest,HttpServletResponseresponse)
throwsServletException,IOException{
 
processRequest(request,response);
}
 
protectedfinalvoidprocessRequest(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));
}
}
}

processRequest方法主要做4项工作。

  1. 得到当前线程的LocaleContext和RequestAttributes,创建新的LocaleContext和RequestAttributes并重新绑定到当前线程。

    调用子类实现的doService()

    重置当前线程的LocaleContext和RequestAttributes

    执行成功后,发布ServletRequestHandledEvent事件。

    2.DispatcherServlet自定义的doService方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    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);
    }
    }
    }</string,object></string,object>

    主要做两部分工作

    1. 如果是include请求,先保存一份request域数据的快照,doDispatch执行过后,将会用快照数据恢复。

      调用doDispatch方法,完成请求转发。

      3.doDispatch方法

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      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++){ actuallyinvokethehandler.= "" applyposthandlemethodsofregisteredinterceptors.= "" handlerinterceptorinterceptor= "interceptors[i];" interceptorindex= "i;" inti= "interceptors.length-1;i" mv= "ha.handle(processedRequest,response,mappedHandler.getHandler());" >= 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);
      }
      }
      }</interceptors.length;i++){>

      很明显这儿是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.总结

      wKioL1g-153C8LZpAACyG_bLg7c573.png

      简单粗暴的总结下

      step1-6: 获取controller

      step5-15 :调用controller方法

      step17-20:渲染view

      其他:aop方式处理拦截统一处理。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM