Spring MVC 源码分析

Spring MVC 源码分析

  • 1. 回顾Servlet
    • 1.1. 什么是Servlet
    • 1.2. Servlet工作模式
    • 1.3. Servlet的工作原理
    • 1.4. 源码分析
      • 1.4.1. Servlet接口
      • 1.4.2. GenericServlet抽象类
      • 1.4.3. HttpServlet抽象类
    • 1.5. Servlet的局限性
  • 2. Spring MVC简介
    • 2.1. 什么是MVC
    • 2.2. 什么是Spring MVC?
    • 2.3. Spring MVC核心组件
    • 2.4. Spring MVC工作流程
  • 3. Spring MVC源码分析
    • 3.1. FrameworkServlet抽象类
    • 3.2. DispatcherServlet类
    • 3.3. 获取HandlerExecutionChain对象
    • 3.4. 根据Handler获取HandlerAdapter
    • 3.5. 调用拦截器的preHandle方法
    • 3.6. 通过HandlerAdapter调用Handler实际处理请求,获取ModelAndView对象
    • 3.7. 调用拦截器的postHandle方法
    • 3.8. 处理分发结果,渲染视图(包含了正常处理和异常情况的处理),将结果输出到客户端
      • 3.8.1. 位置
      • 3.8.2. processDispatchResult方法源码
      • 3.8.3. 如果有异常,进行全局异常处理
      • 3.8.4. 渲染视图
      • 3.8.5. 调用拦截器的 afterCompletion 方法

1. 回顾Servlet

1.1. 什么是Servlet

Servlet is an API that provides many interfaces and classes including documentation.

Servlet is an interface that must be implemented for creating any Servlet.

Servlet is a class that extends the capabilities of the servers and responds to the incoming requests. It can respond to any requests.

其主要功能在于交互式地浏览和修改数据,生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类。

1.2. Servlet工作模式

  1. 客户端发送请求至服务器;
  2. 服务器启动并调用Servlet,Servlet根据客户端请求生成响应内容并将其传给服务器;
  3. 服务器将响应返回客户端;

1.3. Servlet的工作原理

  1. Servlet接口定义了Servlet与servlet容器之间的契约。这个契约是:Servlet容器将Servlet类载入内存,并产生Servlet实例和调用它具体的方法。但是要注意的是,在一个应用程序中,每种Servlet类型只能有一个实例。
  2. 用户请求致使Servlet容器调用Servlet的service()方法,并传入一个ServletRequest对象和一个ServletResponse对象。ServletRequest对象和ServletResponse对象都是由Servlet容器(例如TomCat)封装好的,并不需要程序员去实现,程序员可以直接使用这两个对象。
  3. ServletRequest中封装了当前的Http请求,因此,开发人员不必解析和操作原始的Http数据。ServletResponse表示当前用户的Http响应,程序员只需直接操作ServletResponse对象就能把响应轻松的发回给用户。
  4. 对于每一个应用程序,Servlet容器还会创建一个ServletContext对象。这个对象中封装了上下文(应用程序)的环境详情。每个应用程序只有一个ServletContext。每个Servlet对象也都有一个封装Servlet配置的ServletConfig对象。

1.4. 源码分析

1.4.1. Servlet接口

最原始的Servlet接口有三个主要方法:init、service和destroy;

/**
 * Defines methods that all servlets must implement.
 *
 * @author 	Various
 *
 * @see 	GenericServlet
 * @see 	javax.servlet.http.HttpServlet
 *
 */

public interface Servlet {

    /**
     * Called by the servlet container to indicate to a servlet that the 
     * servlet is being placed into service.
     */

    public void init(ServletConfig config) throws ServletException;

    /**
     * Returns a {@link ServletConfig} object, which contains
     * initialization and startup parameters for this servlet.
     */

    public ServletConfig getServletConfig();
    
    /**
     * Called by the servlet container to allow the servlet to respond to 
     * a request.
     */

    public void service(ServletRequest req, ServletResponse res)
	throws ServletException, IOException;

    /**
     * Returns information about the servlet, such
     * as author, version, and copyright.
     */

    public String getServletInfo();
    
    /**
     * Called by the servlet container to indicate to a servlet that the
     * servlet is being taken out of service. 
     */

    public void destroy();
}

1.4.2. GenericServlet抽象类

  1. GenericServlet defines a generic, protocol-independent servlet.

  2. Spring MVC 源码分析_第1张图片

  3. GenericServlet抽象类包含以下主要方法,可以看出主要还是围绕着init、service和destroy;

    public abstract class GenericServlet implements Servlet, ServletConfig, java.io.Serializable {
       
      /**
        * Called by the servlet container to indicate to a servlet that the
        * servlet is being taken out of service.  See {@link Servlet#destroy}.
        */
    
       public void destroy() { }
    
       /**
        * Called by the servlet container to indicate to a servlet that the
        * servlet is being placed into service.  See {@link Servlet#init}.
        */
    
       public void init(ServletConfig config) throws ServletException {
    		this.config = config;
    		this.init();
       }
    
       /**
        * A convenience method which can be overridden so that there's no need
        * to call super.init(config).
        */
       
       public void init() throws ServletException { }
       
       /**
        * Called by the servlet container to allow the servlet to respond to
        * a request.  See {@link Servlet#service}.
        */
    
       public abstract void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
       
       /**
        * Returns the name of this servlet instance.
        */
    
       public String getServletName() {
           ServletConfig sc = getServletConfig();
           if (sc == null) {
               throw new IllegalStateException(
                   lStrings.getString("err.servlet_config_not_initialized"));
           }
    
           return sc.getServletName();
       }
    }
    
    

1.4.3. HttpServlet抽象类

  1. HttpServlet provides an abstract class to be subclassed to create an HTTP servlet suitable for a Web site.

  2. Spring MVC 源码分析_第2张图片

  3. HttpServlet的主要内容如下,主要是提供了service方法,使得继承该类的方法无需再override。定义了doGet、doPost等一系列方法,但并未给出具体实现。

    public abstract class HttpServlet extends GenericServlet implements java.io.Serializable {
    
       /**
        * Called by the server (via the service method) to
        * allow a servlet to handle a GET request. 
        */
       protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         String protocol = req.getProtocol();
         String msg = lStrings.getString("http.method_get_not_supported");
         if (protocol.endsWith("1.1")) {
             resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
         } else {
             resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
         }
       }
    
       protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         NoBodyResponse response = new NoBodyResponse(resp);
         doGet(req, response);
         response.setContentLength();
       }
       
       protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         String protocol = req.getProtocol();
         String msg = lStrings.getString("http.method_post_not_supported");
         if (protocol.endsWith("1.1")) {
             resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
         } else {
             resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
         }
       }
    
       /**
        *
        * Receives standard HTTP requests from the public
        * service method and dispatches
        * them to the doXXX methods defined in 
        * this class. This method is an HTTP-specific version of the 
        * {@link javax.servlet.Servlet#service} method. There's no
        * need to override this method.
        */
    
       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) {
           // servlet doesn't support if-modified-since, no reason
           // to go through further expensive logic
           doGet(req, resp);
             } else {
           long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
           if (ifModifiedSince < (lastModified / 1000 * 1000)) {
               // If the servlet mod time is later, call doGet()
                           // Round down to the nearest second for a proper compare
                           // A ifModifiedSince of -1 will always be less
               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 {
             //
             // Note that this means NO servlet supports whatever
             // method was requested, anywhere on this server.
             //
    
             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);
         }
       }
     
       /**
        * Dispatches client requests to the protected
        * service method. There's no need to
        * override this method.
        */
       public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
         HttpServletRequest	request;
         HttpServletResponse	response;
    
         try {
             request = (HttpServletRequest) req;
             response = (HttpServletResponse) res;
         } catch (ClassCastException e) {
             throw new ServletException("non-HTTP request or response");
         }
         service(request, response);
       }
    }
    

1.5. Servlet的局限性

Servlet如果需要给客户端返回数据,比如一个HTML文件,需要一行一行的把HTML语句给用Writer输出,早期简单的网页还能应付得住,但是随着互联网的不断发展,网站的内容和功能越来越强大,一个普通的HTML文件可能就达到好几百行,如果在采用使用Servlet去一行一行的输出HTML代码的话,将会非常的繁琐并且浪费大量的时间,且在当时,出现了PHP这种可以内嵌到HTML文件的动态语言,使得制作动态网页变得异常的简单和轻松,因此大量的程序员转上了PHP语言的道路,JAVA的份额急剧减小,当时JAVA的开发者Sun公司为了解决这个问题,也开发出了自己的动态网页生成技术,使得同样可以在HTML文件里内嵌JAVA代码,这就是现在的JSP技术。

2. Spring MVC简介

2.1. 什么是MVC

  1. MVC是模型(Model)、视图(View)、控制器(Controller)的简写,是一种软件设计规范。是将业务逻辑、数据、显示分离的方法来组织代码。MVC主要作用是降低了视图与业务逻辑间的双向耦合。

  2. Model(模型):数据模型,提供要展示的数据,因此包含数据和行为,可以认为是领域模型或JavaBean组件(包含数据和行为),不过现在一般都分离开来:Value Object(数据Dao) 和 服务层(行为Service)。也就是模型提供了模型数据查询和模型数据的状态更新等功能,包括数据和业务。

    View(视图):负责进行模型的展示,一般就是我们见到的用户界面,客户想看到的东西。

    Controller(控制器):接收用户请求,委托给模型进行处理(状态改变),处理完毕后把返回的模型数据返回给视图,由视图负责展示。 也就是说控制器做了个调度员的工作。

  3. 流程:

    1. 用户通过视图层发送请求到服务器,在服务器中请求被Controller接收;
    2. Controller调用相应的Model层处理请求,处理完毕后结果返回到Controller;
    3. Controller再根据请求处理的结果找到对应的View视图,渲染数据后最终响应给浏览器;

Spring MVC 源码分析_第3张图片

  1. MVC不是一种设计模式,而是一种架构模式。

    1. 架构模式:一个架构模式描述软件系统里的基本的结构组织或纲要;架构模式提供一些事先定义好的子系统,指定他们的责任,并给出把他们组织在一起的法则和指南;
    2. 设计模式:一个设计模式提供一种提炼子系统或软件系统中的组织或者他们之间的关系的纲要设计;设计模式描述普遍存在的在相互通信的组件中重复出现的结构,这种结构解决在一定的背景中的具有一般性的设计问题;

2.2. 什么是Spring MVC?

  1. Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架。

  2. Spring MVC的特点:

    1. 轻量级,简单易学;
    2. 高效 , 基于请求响应的MVC框架;
    3. 与Spring兼容性好,无缝结合;
    4. 约定优于配置;
    5. 功能强大:RESTful、数据验证、格式化、本地化、主题等;
    6. 简洁灵活;
  3. Spring的web框架围绕DispatcherServlet设计。DispatcherServlet的作用是将请求分发到不同的处理器。

2.3. Spring MVC核心组件

  1. DispatcherServlet:负责调度其他组件的执行,可以降低不同组件之间的耦合性,是整个Spring MVC的核心模块;
  2. Handler:处理器,完成具体的业务逻辑,相当于Servlet;
  3. HandlerMapping:DispatcherServlet是通过 HandlerMapping把请求映射到不同的Handler;
  4. HandlerInterceptor:处理器拦截器,是一个接口,如果我们需要进行一些拦截处理,可以通过实现该接口完成;
  5. HandlerExecutionChain:处理器执行链,包括两部分内容:Handler和HandlerInterceptor(系统会有一个默认的HandlerInterceptor,如果有额外拦截处理,可以添加拦截器进行设置);
  6. HandlerAdapter:处理器适配器,Handler执行业务方法之前,需要进行一系列的操作包括表单的数据验证、数据类型转换、把表单数据封装到POJO等,这些一系列的操作都是由HandlerAdapter完成,DispatcherServlet通过HandlerAdapter执行不同的Handler;
  7. ModelAndView:封装了模型数据和视图信息,作为Handler的处理结果,返回给DispatcherServlet;
  8. ViewResolver:视图解析器,DispatcherServlet通过它把逻辑视图解析为物理视图,最终把渲染的结果响应给客户端;

2.4. Spring MVC工作流程

Spring MVC 源码分析_第4张图片
Spring MVC 源码分析_第5张图片

  1. 客户端向服务器发送请求,请求被 SpringMVC 前端控制器 DispatcherServlet 捕获;
  2. DispatcherServlet 根据该 URI,调用 HandlerMapping 获得该 Handler 配置的所有相关的对象(包括 Handler 对象以及 Handler 对象对应的拦截器),最后以 HandlerExecutionChain 的形式返回;
  3. DispatcherServlet 根据获得的 Handler,选择一个合适的 HandlerAdapter;
  4. 如果成功获得 HandlerAdapter,此时将开始执行拦截器的 preHandler方法;
  5. 提取 Request 中的数据,填充 handle入参,开始执行 handle 方法,处理请求,在填充 Handler 的入参过程中,根据你的配置,Spring 将帮你做一些额外的工作:
    1. HttpMessageConveter:将请求消息(如 Json、xml 等数据)转换成一个对象,将对象转换为指定的类型信息;
    2. 数据转换:对请求消息进行数据转换。如 String 转换成 Integer、Double 等;
    3. 数据格式化:对请求消息进行数据格式化。如将字符串转换成格式化数字或格式化日期等;
    4. 数据验证:验证数据的有效性(长度、格式等),验证结果存储到 BindingResult 或 Error 中;
  6. handle方法执行完毕后,返回一个ModelAndView对象给DispatcherServlet;
  7. 此时将开始执行拦截器的 postHandle 方法【逆向】;
  8. DispatcherServlet把获取的ModelAndView对象传给ViewResolver视图解析器,来渲染视图;
  9. DispatcherServlet把渲染后的视图返回给客户端;
  10. 渲染视图完毕执行拦截器的 afterCompletion 方法【逆向】;

3. Spring MVC源码分析

3.1. FrameworkServlet抽象类

  1. FrameworkServlet is the base servlet for Spring’s web framework. Provides integration with a Spring application context, in a JavaBean-based overall solution.

  2. Spring MVC 源码分析_第6张图片

  3. HttpServlrtBean抽象类:Simple extension of HttpServlet which treats its config parameters (init-param entries within the servlet tag in web.xml) as bean properties.

  4. 看一下FrameworkServlet抽象类的主要方法,发现把doXXX方法都统一到doService抽象方法上了;

    /**
     * Override the parent class implementation in order to intercept PATCH requests.
     */
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
    		throws ServletException, IOException {
    
    	HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
    	if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
    		processRequest(request, response);
    	}
    	else {
    		super.service(request, response);
    	}
    }
    
    /**
     * Delegate GET requests to processRequest/doService.
     */
    @Override
    protected final void doGet(HttpServletRequest request, HttpServletResponse response)
    		throws ServletException, IOException {
    
    	processRequest(request, response);
    }
    
    /**
     * Delegate POST requests to {@link #processRequest}.
     */
    @Override
    protected final void doPost(HttpServletRequest request, HttpServletResponse response)
    		throws ServletException, IOException {
    
    	processRequest(request, response);
    }
    
    /**
     * Process this request, publishing an event regardless of the outcome.
     * 

    The actual event handling is performed by the abstract * {@link #doService} template method. */ protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long startTime = System.currentTimeMillis(); Throwable failureCause = null; LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); LocaleContext localeContext = buildLocaleContext(request); RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor()); initContextHolders(request, localeContext, requestAttributes); try { doService(request, response); } catch (ServletException | IOException ex) { failureCause = ex; throw ex; } catch (Throwable ex) { failureCause = ex; throw new NestedServletException("Request processing failed", ex); } finally { resetContextHolders(request, previousLocaleContext, previousAttributes); if (requestAttributes != null) { requestAttributes.requestCompleted(); } logResult(request, response, failureCause, asyncManager); publishRequestHandledEvent(request, response, startTime, failureCause); } } /** * Subclasses must implement this method to do the work of request handling, * receiving a centralized callback for GET, POST, PUT and DELETE. */ protected abstract void doService(HttpServletRequest request, HttpServletResponse response) throws Exception;

3.2. DispatcherServlet类

  1. Central dispatcher for HTTP request handlers/controllers, e.g. for web UI controllers or HTTP-based remote service exporters. Dispatches to registered handlers for processing a web request, providing convenient mapping and exception handling facilities.

  2. Spring MVC 源码分析_第7张图片

  3. DispatcherServlet类override了FrameworkServlet的doService方法,并将最终的处理流程放在了doDispatch方法里,该方法很值得研究,写了一些注释,接下来会详细分析带有标号的注释对应的代码。

    /**
     * Process the actual dispatching to the handler.
     */
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    	HttpServletRequest processedRequest = request;
    	HandlerExecutionChain mappedHandler = null;
    	boolean multipartRequestParsed = false;
       
       //获取异步处理管理器,servlet3.0后支持异步处理,可以在子线程中响应用户请求
    	WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    
    	try {
    		ModelAndView mv = null;
    		Exception dispatchException = null;
    
    		try {
           
           // 解析multipart类型的请求,上传文件用的就是multipart类型的请求方式
    			processedRequest = checkMultipart(request);
           // 用来标记是否是multipart类型的请求
    			multipartRequestParsed = (processedRequest != request);
    
    			// 1. 获取HandlerExecutionChain对象
    			mappedHandler = getHandler(processedRequest);
           // 如果没有获取到,就抛异常
    			if (mappedHandler == null) {
    				noHandlerFound(processedRequest, response);
    				return;
    			}
    
           // 2. 根据Handler获取HandlerAdapter
    			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
           // 3. 调用拦截器的preHandle方法,若返回false,处理结束
    			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    				return;
    			}
    
           // 4. 通过HandlerAdapter调用Handler实际处理请求,获取ModelAndView对象
    			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
           // 判断异步请求不是已经开始了,开始了就返回了
    			if (asyncManager.isConcurrentHandlingStarted()) {
    				return;
    			}
    
           // 如果mv对象中没有视图且DispatcherServlet配置了默认的视图,则给mv安排一个默认的视图
    			applyDefaultViewName(processedRequest, mv);
           // 5. 调用拦截器的postHandle方法
    			mappedHandler.applyPostHandle(processedRequest, response, mv);
    		}
    		catch (Exception ex) {
    			dispatchException = ex;
    		}
    		catch (Throwable err) {
    			dispatchException = new NestedServletException("Handler dispatch failed", err);
    		}
         // 6. 处理分发结果,渲染视图(包含了正常处理和异常情况的处理),将结果输出到客户端
    		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    	}
    	catch (Exception ex) {
         // 7. 调用拦截器的afterCompletion方法
    		triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    	}
    	catch (Throwable err) {
         // 7. 调用拦截器的afterCompletion方法
    		triggerAfterCompletion(processedRequest, response, mappedHandler,
    				new NestedServletException("Handler processing failed", err));
    	}
    	finally {
         // 对于异步处理的情况,调用异步处理的拦截器AsyncHandlerInterceptor的afterConcurrentHandlingStarted方法
    		if (asyncManager.isConcurrentHandlingStarted()) {
    			if (mappedHandler != null) {
    				mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
    			}
    		}
    		else {
    			//对于multipart的请求,清理资源,比如文件上传的请求,上传的过程中文件会被保存到临时文件中,这里就会对这些文件继续清理
    			if (multipartRequestParsed) {
    				cleanupMultipart(processedRequest);
    			}
    		}
    	}
    }
    

3.3. 获取HandlerExecutionChain对象

  1. // 1. 获取HandlerExecutionChain对象
    mappedHandler = getHandler(processedRequest);
    
  2. 来看一下getHandler方法:

    /**
     * Return the HandlerExecutionChain for this request.
     */
    @Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    	if (this.handlerMappings != null) {
    		for (HandlerMapping mapping : this.handlerMappings) {
    			HandlerExecutionChain handler = mapping.getHandler(request);
    			if (handler != null) {
    				return handler;
    			}
    		}
    	}
    	return null;
    }
    
  3. 遍历了handlerMappings,分别调用它们的getHandler方法,找到对应的HandlerExecutionChain;

  4. HandlerExecutionChain类中主要包含以下三个属性:

    // 请求处理器,通常就是我们自定义的 controller 对象及方法
    private final Object handler;
    
    // 当前请求匹配到的拦截器列表
    private List<HandlerInterceptor> interceptorList;
    
    // 拦截器索引,用来记录执行到第几个拦截器了
    private int interceptorIndex;
    
  5. 在AbstractHandlerMapping抽象类中,getHandler方法首先调用了getHandlerInternal方法,通过寻找、读取配置文件,找到request对应的handler,然后调用了getHandlerExecutionChain方法,通过路径匹配,找到对应的interceptors;

3.4. 根据Handler获取HandlerAdapter

  1.     // 2. 根据Handler获取HandlerAdapter
    	HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
  2. 来看一下getHandlerAdapter方法:

    /**
     * Return the HandlerAdapter for this handler object.
     */
    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    	if (this.handlerAdapters != null) {
    		for (HandlerAdapter adapter : this.handlerAdapters) {
    			if (adapter.supports(handler)) {
    				return adapter;
    			}
    		}
    	}
    	throw new ServletException("No adapter for handler [" + handler +
    			"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }
    
  3. 遍历handlerAdapters,找到能够处理当前 Handler 的HandlerAdapter,如果没找到会报错;

3.5. 调用拦截器的preHandle方法

  1.    // 3. 调用拦截器的preHandle方法,若返回false,处理结束
         				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
         					return;
         				}
    
  2. 来看下applyPreHandle方法:

    /**
     * Apply preHandle methods of registered interceptors.
     */
    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    	HandlerInterceptor[] interceptors = getInterceptors();
    	if (!ObjectUtils.isEmpty(interceptors)) {
    		for (int i = 0; i < interceptors.length; i++) {
    			HandlerInterceptor interceptor = interceptors[i];
    			if (!interceptor.preHandle(request, response, this.handler)) {
    				triggerAfterCompletion(request, response, null);
    				return false;
    			}
    			this.interceptorIndex = i;
    		}
    	}
    	return true;
    }
    
  3. 该方法首先循环调用拦截器的preHandle方法,如果某个拦截器的preHandle方法返回 false,则调用triggerAfterCompletion方法,且记录了拦截器的执行位置;

  4. 来看下triggerAfterCompletion方法:

    /**
     * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
     * Will just invoke afterCompletion for all interceptors whose preHandle invocation
     * has successfully completed and returned true.
     */
    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
    		throws Exception {
    
    	HandlerInterceptor[] interceptors = getInterceptors();
    	if (!ObjectUtils.isEmpty(interceptors)) {
    		for (int i = this.interceptorIndex; i >= 0; i--) {
    			HandlerInterceptor interceptor = interceptors[i];
    			try {
    				interceptor.afterCompletion(request, response, this.handler, ex);
    			}
    			catch (Throwable ex2) {
    				logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
    			}
    		}
    	}
    }
    
  5. 该方法反向依次调用那些 preHandle 方法返回 ture 的拦截器的 afterCompletion 方法;

3.6. 通过HandlerAdapter调用Handler实际处理请求,获取ModelAndView对象

  1.    // 4. 通过HandlerAdapter调用Handler实际处理请求,获取ModelAndView对象
         				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
  2. 来看下handle方法,handle方法会走到org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod:

    /**
     * Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView}
     * if view resolution is required.
     */
    @Nullable
    protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
    		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
    	ServletWebRequest webRequest = new ServletWebRequest(request, response);
    	try {
    		WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
    		ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
    
    		ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
    		if (this.argumentResolvers != null) {
    			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
    		}
    		if (this.returnValueHandlers != null) {
    			invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
    		}
    		invocableMethod.setDataBinderFactory(binderFactory);
    		invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
    
    		ModelAndViewContainer mavContainer = new ModelAndViewContainer();
    		mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
    		modelFactory.initModel(webRequest, mavContainer, invocableMethod);
    		mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
    
    		AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
    		asyncWebRequest.setTimeout(this.asyncRequestTimeout);
    
    		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    		asyncManager.setTaskExecutor(this.taskExecutor);
    		asyncManager.setAsyncWebRequest(asyncWebRequest);
    		asyncManager.registerCallableInterceptors(this.callableInterceptors);
    		asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
    
    		if (asyncManager.hasConcurrentResult()) {
    			Object result = asyncManager.getConcurrentResult();
    			mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
    			asyncManager.clearConcurrentResult();
    			LogFormatUtils.traceDebug(logger, traceOn -> {
    				String formatted = LogFormatUtils.formatValue(result, !traceOn);
    				return "Resume with async result [" + formatted + "]";
    			});
    			invocableMethod = invocableMethod.wrapConcurrentResult(result);
    		}
    
    		invocableMethod.invokeAndHandle(webRequest, mavContainer);
    		if (asyncManager.isConcurrentHandlingStarted()) {
    			return null;
    		}
    
    		return getModelAndView(mavContainer, modelFactory, webRequest);
    	}
    	finally {
    		webRequest.requestCompleted();
    	}
    }
    
  3. 上述方法主要做了三件事:

    1. 组装目标方法需要的参数;

      org.springframework.web.method.support.InvocableHandlerMethod#getMethodArgumentValues
      
      1. 在该方法中,使用HandlerMethodArgumentResolver进行解析请求,得到参数;

      2. HandlerMethodArgumentResolver有很多实现类,归纳如下:

        实现类 对应的控制器参数 说明
        PathVariableMapMethodArgumentResolver @PathVariable 标注参数 从 url 中提取参数的值
        RequestHeaderMethodArgumentResolver @RequestHeader 标注参数 从 http 头中提取参数值
        RequestParamMethodArgumentResolver @RequestParam 标注参数 从http 请求参数中获取值
        RequestResponseBodyMethodProcessor @RequestBody 标注参数 提取 body 数据,转换为参数类型
        ServletResponseMethodArgumentResolver ServletResponse、OutputStream、Writer 这 3 种类型的参数 这几种类型用来控制 http 请求的响应输出流
        HttpEntityMethodProcessorHttpEntity HttpEntity 类型的参数 HttpEntity 中包含了 http 请求头和 body 的所有信息
        ExpressionValueMethodArgumentResolver @Value 标注的参数 spel 表达式,从 spring 容器中获取值
        MapMethodProcessor 参数为 Map 或者子类型 -
        ModelMethodProcessor 参数为 org.springframework.ui.Model 或子类型 -
        ModelAttributeMethodProcessor @ModelAttribute 标注的参数 -
    2. 通过反射调用处理请求的目标方法,获取方法的返回值;

      org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle
      
    3. 对方法的返回值进行处理;

      org.springframework.web.method.support.HandlerMethodReturnValueHandler
      
      1. 该接口有两个方法:

        	/**
        	 * Whether the given {@linkplain MethodParameter method return type} is
        	 * supported by this handler
        	 */
        	boolean supportsReturnType(MethodParameter returnType);
        
        	/**
        	 * Handle the given return value by adding attributes to the model and
        	 * setting a view or setting the
        	 * {@link ModelAndViewContainer#setRequestHandled} flag to {@code true}
        	 * to indicate the response has been handled directly.
        	 */
        	void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
        			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception;
        
      2. 该接口具有很多实现类:Spring MVC 源码分析_第8张图片

      3. 归纳如下:

        实现类 说明
        ViewNameMethodReturnValueHandler 返回值为视图名称时的解析器
        MapMethodProcessor 返回值为 Map 的解析器
        StreamingResponseBodyReturnValueHandler 返回值为 ResponseEntity 类型时的解析器
        DeferredResultMethodReturnValueHandler 返回值为 DeferredResult 类型时的解析器,表示异步请求
        CallableMethodReturnValueHandler 返回值为 Callable 类型时的解析器,表示异步请求
        ModelMethodProcessor 返回值为 Model 类型时的解析器
        ModelAndViewMethodReturnValueHandler 返回值为 ModelAndView 类型时的解析器
        RequestResponseBodyMethodProcessor 方法上标注有@ResponseBody 注解时返回值的解析器
        HttpEntityMethodProcessor 返回值为 HttpEntity 类型但是非 RequestEntity 类型时的解析器
      4. 以其中的RequestResponseBodyMethodProcessor为例,来看下源码:

        	@Override
        	public boolean supportsReturnType(MethodParameter returnType) {
        		// 判断类上或者目标方法上是否有@ResponseBody注解
        		return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) ||
        				returnType.hasMethodAnnotation(ResponseBody.class));
        	}
        
        	@Override
        	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
        			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
        			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
            // 1:标注为请求已处理,因为当前handleReturnValue方法会直接将结果输出到客户端,所以后续就不需要再进行视图渲染了,表示请求已经被处理了
            mavContainer.setRequestHandled(true);
        		ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
        		ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
        
            // 2:将结果输出到客户端
        		writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
        	}
        
      5. 注意,并不是所有的实现类的handleReturnValue方法都将结果直接返回给客户端了,有些是需要渲染的;

3.7. 调用拦截器的postHandle方法

  1.    // 5. 调用拦截器的postHandle方法
         				mappedHandler.applyPostHandle(processedRequest, response, mv);
    
  2. 来看下applyPostHandle方法:

    /**
     * Apply postHandle methods of registered interceptors.
     */
    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
    		throws Exception {
    
    	HandlerInterceptor[] interceptors = getInterceptors();
    	if (!ObjectUtils.isEmpty(interceptors)) {
    		for (int i = interceptors.length - 1; i >= 0; i--) {
    			HandlerInterceptor interceptor = interceptors[i];
    			interceptor.postHandle(request, response, this.handler, mv);
    		}
    	}
    }
    
  3. 逆序调用拦截器的postHandle方法;

3.8. 处理分发结果,渲染视图(包含了正常处理和异常情况的处理),将结果输出到客户端

3.8.1. 位置

  1. // 6. 处理分发结果,渲染视图(包含了正常处理和异常情况的处理),将结果输出到客户端
    		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    

3.8.2. processDispatchResult方法源码

	/**
	 * Handle the result of handler selection and handler invocation, which is
	 * either a ModelAndView or an Exception to be resolved to a ModelAndView.
	 */
	private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {

		boolean errorView = false;

		if (exception != null) {
			if (exception instanceof ModelAndViewDefiningException) {
				logger.debug("ModelAndViewDefiningException encountered", exception);
				mv = ((ModelAndViewDefiningException) exception).getModelAndView();
			}
			else {
				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
				mv = processHandlerException(request, response, handler, exception);
				errorView = (mv != null);
			}
		}

		// Did the handler return a view to render?
		if (mv != null && !mv.wasCleared()) {
			render(mv, request, response);
			if (errorView) {
				WebUtils.clearErrorRequestAttributes(request);
			}
		}
		if (mappedHandler != null) {
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}

3.8.3. 如果有异常,进行全局异常处理

  1. mv = processHandlerException(request, response, handler, exception);
    
  2. 看一下processHandlerException方法:

    /**
     * Determine an error ModelAndView via the registered HandlerExceptionResolvers.
     */
    @Nullable
    protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
    		@Nullable Object handler, Exception ex) throws Exception {
    
    	ModelAndView exMv = null;
    	if (this.handlerExceptionResolvers != null) {
    		for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
    			exMv = resolver.resolveException(request, response, handler, ex);
    			if (exMv != null) {
    				break;
    			}
    		}
    	}
    	if (exMv != null) {
    		WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
    		return exMv;
    	}
    
    	throw ex;
    }
    
  3. 该方法主要是遍历HandlerExceptionResolver的resolveException方法来处理异常;

3.8.4. 渲染视图

  1. render(mv, request, response);
    
  2. 看一下render方法:

    /**
     * Render the given ModelAndView.
     */
    protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    	View view;
    	String viewName = mv.getViewName();
    	if (viewName != null) {
    		// We need to resolve the view name.
    		view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
    	}
    	else {
    		// No need to lookup: the ModelAndView object contains the actual View object.
    		view = mv.getView();
    	}
    	view.render(mv.getModelInternal(), request, response);
    }
    
    
  3. 该方法主要做了两件事:

    1. 调用resolveViewName方法解析视图名称得到 View;

      1. 最终是在org.springframework.web.servlet.view.UrlBasedViewResolver#buildView中拼接了prefix和suffix;
    2. 调用render方法渲染视图;

      1. 看一下render方法,发现最终走到org.springframework.web.servlet.view.AbstractView#renderMergedOutputModel方法中,以其实现类override的方法org.springframework.web.servlet.view.InternalResourceView#renderMergedOutputModel为例:

        protected void renderMergedOutputModel(
                Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
         
            // 将model中的数据遍历后放在request中(request.setAttribute(name,value))
            exposeModelAsRequestAttributes(model, request);
         
            // 获取跳转的页面的路径
            String dispatcherPath = prepareForRendering(request, response);
         
            // 调用getRequestDispatcher得到RequestDispatcher对象
            RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
         
            //实现页面跳转
            if (useInclude(request, response)) {
                rd.include(request, response);
            }else {
                rd.forward(request, response);
            }
        }
        

3.8.5. 调用拦截器的 afterCompletion 方法

  1. if (mappedHandler != null) {
     			mappedHandler.triggerAfterCompletion(request, response, null);
     		}
    
  2. 来看一下这部分源码:

    /**
     * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
     * Will just invoke afterCompletion for all interceptors whose preHandle invocation
     * has successfully completed and returned true.
     */
    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
    		throws Exception {
    
    	HandlerInterceptor[] interceptors = getInterceptors();
    	if (!ObjectUtils.isEmpty(interceptors)) {
    		for (int i = this.interceptorIndex; i >= 0; i--) {
    			HandlerInterceptor interceptor = interceptors[i];
    			try {
    				interceptor.afterCompletion(request, response, this.handler, ex);
    			}
    			catch (Throwable ex2) {
    				logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
    			}
    		}
    	}
    }
    
  3. 主要是反向调用拦截器的afterCompletion方法;

你可能感兴趣的:(Java语言,Java,EE,spring,mvc,servlet)