SpringMVC源码分析

一般用户从浏览器发出的请求会先到我们的web服务器(如:Nginx、Apache等),然后转发至应用服务器(如:Tomcat等),而Tomcat是Servlet容器,掌握着Servlet的生命周期,它接收、处理遵循Servlet规范的请求并返回结果,Tomcat的功能可以简单理解成将浏览器的请求封装成javax.servlet.http.HttpServletRequest和javax.servlet.http.HttpServletResponse两个对象传送给我们用JAVA编写的应用程序。所以我们可以断定我们的程序是能够处理Servlet请求,那么我们带着验证这个问题去阅读SpringMVC的源码,看SpringMVC框架是怎样帮助我们的程序做到完美处理Servlet请求的。

回忆刚工作接触的Spring项目时,在我们的工程里的web.xml中总是有这样的配置

<servlet>
    <servlet-name>springServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>springServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

后来了解到这样的配置使得在我们的应用容器或者说Servlet容器启动的时候便启动org.springframework.web.servlet.DispatcherServlet这个Servlet。而这个Servlet就是用来处理用户请求的。

首先我们来看一下DispatcherServlet的类图
在这里插入图片描述
从类图中我们可以看出DispatcherServlet最终实现了Servlet的中所有的方法。

现在我们可以通过查看源码去查看相关的调用链路。

现在假如我们在浏览器通过Get方式请求这个接口
在这里插入图片描述
首先会到达HttpServlet的service方法。方法代码如下:

protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
        String method = req.getMethod();
    if (method.equals(METHOD_GET)) {
        long lastModified = getLastModified(req);
        if (lastModified == -1) {
            doGet(req, resp);
        } else {
            long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
            if (ifModifiedSince < lastModified) {
                maybeSetLastModified(resp, lastModified);
                doGet(req, resp);
            } else {
                resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            }
        }

    } else if (method.equals(METHOD_HEAD)) {
        long lastModified = getLastModified(req);
        maybeSetLastModified(resp, lastModified);
        doHead(req, resp);

    } else if (method.equals(METHOD_POST)) {
        doPost(req, resp);
        
    } else if (method.equals(METHOD_PUT)) {
        doPut(req, resp);
    } else if (method.equals(METHOD_DELETE)) {
        doDelete(req, resp);
    } else if (method.equals(METHOD_OPTIONS)) {
        doOptions(req,resp);   
    } else if (method.equals(METHOD_TRACE)) {
        doTrace(req,resp);    
    } else {
        String errMsg = lStrings.getString("http.method_not_implemented");
        Object[] errArgs = new Object[1];
        errArgs[0] = method;
        errMsg = MessageFormat.format(errMsg, errArgs);
        resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
    }
}

该方法以及以后的源码中的其他方法中的细节暂时都忽略,以了解主要逻辑为当前阶段的目的。

service方法中会调用doGet(req, resp);方法,查看通过DispatcherServlet类去调用的doGet(req, resp);方法是调用的org.springframework.web.servlet.FrameworkServlet#doGet的方法,代码如下:

protected final void doGet(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
    this.processRequest(request, response);
  }

再查看org.springframework.web.servlet.FrameworkServlet#processRequest的方法,主要代码如下:

protected final void processRequest(HttpServletRequest request, HttpServletResponse response) 
throws ServletException, IOException {
    long startTime = System.currentTimeMillis();
    Throwable failureCause = null;
    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
    LocaleContext localeContext = this.buildLocaleContext(request);
    RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
    ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new 		      		   FrameworkServlet.RequestBindingInterceptor(null));
    this.initContextHolders(request, localeContext, requestAttributes);

    try {
     this.doService(request, response);
    } catch (ServletException var17) {
      failureCause = var17;
      throw var17;
    } catch (IOException var18) {
      failureCause = var18;
      throw var18;
    } catch (Throwable var19) {
      failureCause = var19;
      throw new NestedServletException("Request processing failed", var19);
    } finally {
	      this.resetContextHolders(request, previousLocaleContext, previousAttributes);
	      if (requestAttributes != null) {
	        requestAttributes.requestCompleted();
	      }
	      
     this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
    }    
  }

继续查看查看通过DispatcherServlet对象去调用的doService方法是org.springframework.web.servlet.DispatcherServlet#doService
主要代码如下:

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
   //省略暂时不用关心的代码
    try {
      this.doDispatch(request, response);
    } finally {
      if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
        this.restoreAttributesAfterInclude(request, attributesSnapshot);
      }  
    }
  }

继续查看通过DispatcherServlet对象调用的doDispatch方法org.springframework.web.servlet.DispatcherServlet#doDispatch


org.springframework.web.servlet.DispatcherServlet#doDispatch方法是SpringMVC方法的核心方法。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {
      try {
        ModelAndView mv = null;
        Object dispatchException = null;

        try {
          //检查、处理二进制数据请求
          processedRequest = this.checkMultipart(request);
          multipartRequestParsed = processedRequest != request;
          //获取Handler
          mappedHandler = this.getHandler(processedRequest);
          if (mappedHandler == null || mappedHandler.getHandler() == null) {
            this.noHandlerFound(processedRequest, response);
            return;
          }
          //获取HandlerAdapter
          HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
          String method = request.getMethod();
          boolean isGet = "GET".equals(method);
          if (isGet || "HEAD".equals(method)) {
            long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
            if (this.logger.isDebugEnabled()) {
              this.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;
          }
          //处理请求,获得mv
          mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
          if (asyncManager.isConcurrentHandlingStarted()) {
            return;
          }

          this.applyDefaultViewName(processedRequest, mv);
          mappedHandler.applyPostHandle(processedRequest, response, mv);
        } catch (Exception var20) {
          dispatchException = var20;
        } catch (Throwable var21) {
          dispatchException = new NestedServletException("Handler dispatch failed", var21);
        }

        this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
      } catch (Exception var22) {
        this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
      } catch (Throwable var23) {
        this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
      }

    } finally {
      if (asyncManager.isConcurrentHandlingStarted()) {
        if (mappedHandler != null) {
          mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
        }
      } else if (multipartRequestParsed) {
        this.cleanupMultipart(processedRequest);
      }

    }
  }

刚开始我们可能无法理解Spring中为什么代码逻辑要这样编写的原因,所以理解起来比较困难,看得云里雾里的。
以上调用链路用下面的图总结一下,便于加深影响。(第一次画时序图,感觉不太对)
在这里插入图片描述

现在会过头看看SpringMVC为什么要通过getHandler去拿到一个HandlerExecutionChain,这个的内部结构如下
在这里插入图片描述
在一定程度上我们可以把Handler理解成就是我们的业务处理器(Controller)。拿到Handler之后需要通过getHandlerAdapter去找到能处理该类型Handler的Adapter。

以上我们分析的Spring处理请求的链路是基于XML配置的源码解析。如果你是通过注解(Annotation)的方式去配置的Bean,那么Spring的处理方式流程还是一样,里面的实际处理getHandlergetHandlerAdapter对象会有不同,所以Spring是灵活可扩展的框架,以后版本如果有其他的方式去配置Spring也很方便。getHandlergetHandlerAdapter内部的处理逻辑的模式保证了SpringMVC框架的高度可扩展性。

springframework4.3.0.RELEASE版本中org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping已经标注过时(@Deprecated),所以无论哪种配置方式getHandler的实际处理对象都是org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
通过注解(Annotation)方式getHandlerAdapter的实际处理对象是

 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值