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

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

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

概览

SpringMVC源码分析(3)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

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.总结

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

      简单粗暴的总结下

      step1-6: 获取controller

      step5-15 :调用controller方法

      step17-20:渲染view

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

上一篇:MySQL基础2


下一篇:Myeclipse常用优化2