zoukankan      html  css  js  c++  java
  • 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方式处理拦截统一处理。

  • 相关阅读:
    入门篇:Ubuntu用apache做web服务器
    Linux上vi(vim)编辑器使用教程
    vim打开文档和多文档编辑
    vim常用命令
    进行有效编辑的七种习惯
    Ubuntu Nginx 开机自启动
    UBUNTU SERVER 12.04搭建PHP环境
    ubuntu下安装Apache+PHP+Mysql
    Ubuntu 12.04下LAMP安装配置
    data warehouse 1.0 vs 2.0
  • 原文地址:https://www.cnblogs.com/caolei1108/p/6214001.html
Copyright © 2011-2022 走看看