SpringMVC 4.3 源码分析之 DispatcherServlet

1. Spring MVC 概述

SpringMVC, 一个围绕 HttpServlet 实现: handler 映射, handler 适配, 视图解析, 本地化, 时区和主题解析以及文件上传等功能的 MVC 框架!
其主要通过以下主件构成:

1. DispatcherServlet:  继承 HttpServlet 的Http 请求中央分发器, 在其初始化策略里面注册了处理请求的handlerAdapter, 提供请求映射的 handlerMapping 以及异常处理机制
2. Controller:         MVC(Model–view–controller)中的C, 这个Controller在SpringMVC中主要体现在注解@Controller, 接口 org.springframework.web.servlet.mvc.Controller <-- 意指处理请求的角色
3. ControllerAdvice:   Controller 增强器, 这里的Advice可以理解为 AOP 里面的 Advice; 这里主要体现在通过 @ControllerAdvice 注解修饰的类
4. HandlerMapping:     处理请求 request 与请求处理器之间映射关系的类, 默认 RequestMappingHandlerMapping
5. HandlerAdapter:     一个激活 Handler 的适配器, 这个类其实是DispatcherServlet扩展性的一个体现, 所有的请求都交给 HandlerAdapter.handle来进行处理, 则针对不同的 Handler(有继承 Controller接口的, 有通过 @RequestMapping 通过反射激活的), 而 HandlerAdapter 来适配不同的Handler
6. HttpMessageConverter:            通过 HttpServletRequest 数据流中的数据转话成 Handler 方法参数的转换器, 试想我们Http请求时 Http Body 里面的数据有通过 表单提交的, 有Json 格式的字符串, 这时就需要有对应的转换器将对应格式的请求数据转换成参数
7. HandlerMethodArgumentResolver:   Handler方法中参数的解析器,其主要分成 基于参数上的注解的参数解析器, 基于参数类型的参数解析器(PS: 注意上面 HttpMessageConverter 是参数转换器, 转换器服务于解析器)
8. HandlerMethodReturnValueHandler: Handler返回值处理器, 其主要分为 基于注解的返回值处理器, 单一目的返回值处理器
9. HandlerExceptionResolver:        Handler 异常处理器, 这里主要是针对异常类型的处理与针对注解中异常信息的处理两类
10. ViewResolver:      视图解析器
2. DispatcherServlet

DispatcherServlet 其实是一个 HttpServlet 的子类, 但它又不是简简单单一个 HttpServlet; 其 UML 图如下:


DispatcherServlet.png

上图中主要有以下角色:

1. ApplicationContextAware: Spring IOC 容器中的Aware 接口, 通过这个接口能让 DispatcherServlet获取对应 AppplicationContext
2. EnvironmentAware: 让 DispatcherServlet 具有 ConfigurableEnvironment 的能力
3. FrameoworkServlet: 每个DispatcherServlet 都会有对应的一个 ApplicationContext, ApplicationContext对应的创建及配置操作就在这里完成的
3. DispatcherServlet 启动

首先 DispatcherServlet 是一个 HttpServlet, 所以其初始化的过程在其父类 FrameworkServlet 的父类 HttpServletBean 里面发生

// 功能: 简单的获取 servlet 中的 <init-param> 参数并绑定到 BeanWrapper 对象中, 并通过 initServletBean() 方法供子类完善其余功能
// 开始初始化 spring mvc servlet, 并实例化相应的 PropertyValues 供子类调用
@Override
public final void init() throws ServletException {
    if (logger.isDebugEnabled()) {
        logger.debug("Initializing servlet '" + getServletName() + "'");
    }
    // 获取 Servlet的初始化参数, 对 Bean 属性进行配置
    // Set bean properties from init parameters.
    // 此处便是读取 <servlet> 节点中的 <init-param> 参数保存至 MutablePropertyValues#propertyValueList 集合中
    // 解析 init-param 并封装在 pvs 中
    PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
    if (!pvs.isEmpty()) {
        try {
            // 将当前的这个 Servlet 类转化为一个 BeanWrapper, 从而能够以 Spring 的方式来对 init-param 的值进行注入
            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);   // 将指定实例转化为 Spring 中可以处理的 BeanWrapper 类型的实例
            ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
            // 注册自定义属性编辑器, 一旦遇到 Resource 类型的属性将会使用 ResourceEditor 进行解析
            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
            // 默认为空, 留给子类覆盖
            initBeanWrapper(bw);
            // 通过 BeanWrapper 将 getServletConfig() 中的属性配置到 DispatcherServlet
            bw.setPropertyValues(pvs, true);
        }
        catch (BeansException ex) {
            if (logger.isErrorEnabled()) {
                logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
            }
            throw ex;
        }
    }
    // 调用 子类的 initServletBean 进行具体的初始化
    // Let subclasses do whatever initialization they like. 供子类覆写
    initServletBean();
}

如上所示, 在HttpServletBean的init方法里面主要做了:

1. 将 Servlet配置的信息通过 ServletConfigPropertyValues 封装成 PropertyValues
2. 基于 DispatcherServlet 为Target构建一个封装类 BeanWrapper
3. 将上面的 PropertyValues 设置到 DispatcherServlet上 <-- 其实就是在 web.xml 中配置的 Spring-xx.xml 的配置信息
4. 调用模版方法 initServletBean 来进行后续的操作

接着就是 FrameworkServlet, 其中主要是 获取ServletContext(这里指Tomcat 中的 ServletContext)中的 ApplicationContext, 创建属于当前DispatcherServlet的ApplicationContext, 接着就调用 onRefresh 来初始化DispatcherServlet 中常用的组件

protected WebApplicationContext initWebApplicationContext() {
    // 这里调用 WebApplicationContextUtils 静态类来得到根 ApplicationContext, 这个根上下文是保存在 ServletContext 中的
    // 使用这个根上下文作为当前 MVC 上下文的双亲ApplicationContext
    // 一般来说 spring 初始化时间比 spring mvc 要早, 所有 rootApplicationContext 一般都存在
    WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;
    // 再而尝试从 ServletContext 的 'contextAttribute' 对应的值去获取
    if (wac == null) wac = findWebApplicationContext();
    // 不然则创建新的 WebApplicationContext
    if (wac == null) wac = createWebApplicationContext(rootContext);     
    // 调用子类的 onRefresh(wac) 方法初始化 springmvc, onRefresh 在其子类 DispatcherServlet 中进行了重写
    if (!this.refreshEventReceived) onRefresh(wac);
    return wac;
}
PS: 上面省略了很多不是非常重要的代码|注释

而DispatcherServlet 中主要是初始化其主要使用的组件:

protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context); // 加载 beanFactory 中的 multipartResolver bean对象, 适用于处理文件上传的操作
    initLocaleResolver(context);    // 获取 id="localResolver" 的 bean 对象, 如果没有则使用默认的 org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver 类创建的 Bean 对象
    initThemeResolver(context);     // 寻找 id = "themeResolver" 的 bean 对象, 没有则默认使用 org.springframework.web.servlet.theme.FixedThemeResolver 作为 Bean 对象
    initHandlerMappings(context);   // 初始化 对资源访问的映射处理请求, 后者是注解方式的映射请求
    initHandlerAdapters(context);   // 初始化 Handler 适配器 一般是从 ApplicationContext 中获取所有的 HandlerAdapter, 若还是没有则通过 DispatcherServlet.properties 来进行获取
    initHandlerExceptionResolvers(context);    // 初始化 Handler 异常处理器 一般是从 ApplicationContext 中获取所有的 HandlerExceptionResolver, 若还是没有则通过 DispatcherServlet.properties 来进行获取
    initRequestToViewNameTranslator(context);  // 通过 ApplicationContext 获取 id=viewNameTranslator 的 RequestToViewNameTranslator
    initViewResolvers(context);                // 初始化 视图解析器 一般是从 ApplicationContext 中获取所有的 ViewResolver, 若还是没有则通过 DispatcherServlet.properties 来进行获取
    initFlashMapManager(context);   // 初始化 FlashMap 管理器, 主要通过 ApplicationContext 获取 FlashMapManager
}

在初始化组件时通常先从 ApplicationContext 获取对应组件, 若此时没有获取到, 则根据 DispatcherServlet.properties 配置的信息来初始化组件

4. DispatcherServlet 主要组件

DispatcherServlet 中的组件主要分为加载数据的配置参数与处理Request请求的组件

private static final Properties defaultStrategies;

// DispatcherServlet 静态块读取 DispatcherServlet.properties 其中包含默认的策略实现
static {
    // Load default strategy implementations from properties file.
    // This is currently strictly internal and not meant to be customized
    // by application developers.
    try {
        ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
        defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
    }
    catch (IOException ex) {
        throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
    }
}
// 是否 获取所有的 HandlerMapping
/** Detect all HandlerMappings or just expect "handlerMapping" bean? */
private boolean detectAllHandlerMappings = true;

// 是否 获取所有的HandlerAdapter
/** Detect all HandlerAdapters or just expect "handlerAdapter" bean? */
private boolean detectAllHandlerAdapters = true;

// 是否获取所有的异常处理器
/** Detect all HandlerExceptionResolvers or just expect "handlerExceptionResolver" bean? */
private boolean detectAllHandlerExceptionResolvers = true;

// 是否获取所有的视图处理器
/** Detect all ViewResolvers or just expect "viewResolver" bean? */
private boolean detectAllViewResolvers = true;

// 在处理请求时, 若没找到对应 handler, 则是否报出异常
/** Throw a NoHandlerFoundException if no Handler was found to process this request? **/
private boolean throwExceptionIfNoHandlerFound = false;

// 在处理了一个 includeRequest 后是否需要恢复原先 HttpServletRequest 中存储的信息, 见 restoreAttributesAfterInclude <-- 这里是恢复的过程
/** Perform cleanup(清除) of request attributes after include request? */
private boolean cleanupAfterInclude = true;

// 将 HttpServletRequest 解析成 MultipartHttpServletRequest 的类
/** MultipartResolver used by this servlet */
private MultipartResolver multipartResolver;

// 解决  国际化问题的类
/** LocaleResolver used by this servlet */
private LocaleResolver localeResolver;

// 解决 主题的类 <-- 这个用得比较少
/** ThemeResolver used by this servlet */
private ThemeResolver themeResolver;

// Handler 映射处理器类
/** List of HandlerMappings used by this servlet */
private List<HandlerMapping> handlerMappings;

// Handler 处理适配器, 适配不同的 Handler
/** List of HandlerAdapters used by this servlet */
private List<HandlerAdapter> handlerAdapters;

// 处理请求过程中的异常处理器
/** List of HandlerExceptionResolvers used by this servlet */
private List<HandlerExceptionResolver> handlerExceptionResolvers;

// 将 HttpServletRequest 转换成 viewName 的处理器
/** RequestToViewNameTranslator used by this servlet */
private RequestToViewNameTranslator viewNameTranslator;

// 将 FlashMap(key <-> value,value 1对多) 与 HttpServletRequest 进行同步等操作
/** FlashMapManager used by this servlet */
private FlashMapManager flashMapManager;

// 视图解析处理器
/** List of ViewResolvers used by this servlet */
private List<ViewResolver> viewResolvers;
5. DispatcherServlet 对请求的处理

首先 DispatcherServlet 是一个 HttpServlet, 所以其处理请求都是通过其 service(HttpServletRequest request, HttpServletResponse response) 方法,而针对真部分 FrameworkServlet 进行了一些主逻辑的设置(设置一些请求必需的数据, 放置在 ThreadLocal 中)

protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // 记录当前时间, 用于计算 web 请求的处理时间
    long startTime = System.currentTimeMillis();
    Throwable failureCause = null;
    //  ThreadLocal 中获取 本地化相关的数据 <-- 这是先前请求的
    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
    //  构建本次请求 HttpServletRequest 的 LocaleContext, 主要还是从 Session | Cookie 中获取对应的属性
    LocaleContext localeContext = buildLocaleContext(request);
    // 从 ThreadLocal 中获取 RequestAttributes <-- 存储请求的信息, 主要还是 HttpServletRequest 中的一些信息
    RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
    // 基于 Request, Response 构建 ServletRequestAttributes
    ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
    // 在 Request 中存储 web 异常处理器
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    // 在异常处理器中绑定拦截器
    asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
    // 将 localeContext, requestAttributes 绑定到 ThreadLocal 中
    initContextHolders(request, localeContext, requestAttributes);

    try {
        doService(request, response);  // 交给 子类来处理请求
    }
    finally {
        // 恢复请求前设置在 ThreadLocal 中设置的数据
        resetContextHolders(request, previousLocaleContext, previousAttributes);
        if (requestAttributes != null) requestAttributes.requestCompleted();
        // 在 Spring 容器中发布 ServletRequestHandledEvent 事件
        publishRequestHandledEvent(request, response, startTime, failureCause);
    }
}

上面代码主要是构建 LocaleContext, ServletRequestAttributes 放置到 ThreadLocal 中, 接着调用 doService 方法进行处理, 最后在 finally 中恢复先前 ThreadLocal 中存储的数据(PS: 在Spring中真正做事情的方法往往是 do开头的方法名), 而在整个处理过程中还需要要一些数据放置在 HttpServletRequest 中, 这一部分的操作就在 DispatcherServlet.doService 方法

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // Keep a snapshot of the request attributes in case of an include,
    // to be able to restore the original attributes after the include.
    Map<String, Object> attributesSnapshot = null;
    // 判断请求是否是一个 includeRequest, 若是的话, 则通过 attributesSnapshot 将 HttpServletRequest 里面的数据暂且存起来
    if (WebUtils.isIncludeRequest(request)) {
        attributesSnapshot = new HashMap<String, Object>();
        // 获取 HttpServletRequest 里面的属性
        Enumeration<?> attrNames = request.getAttributeNames();
        while (attrNames.hasMoreElements()) {
            String attrName = (String) attrNames.nextElement();
            if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
                // 将 HttpServletRequest 里面的信息, 存储到 attributesSnapshot 里面
                attributesSnapshot.put(attrName, request.getAttribute(attrName));
            }
        }
    }

    // 对 HTTP 请求参数进行快照处理
    // Make framework objects available to handlers and view objects.
    // 设置 ApplicationContext
    request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
    // 设置国际化处理器
    request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
    // 设置主题处理器
    request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
    // 设置 Theme
    request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
    // 取回与 HttpServletRequest 相匹配的 FlashMap
    FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
    if (inputFlashMap != null) {    // 若 inputFlashMap != null, 则还是存储到 HttpServletRequest 中
        request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
    }
    // 构建一个 FlashMap 到 HttpServletRequest 中
    request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
    // 设置 flashMapManager <- 将 FlashMap(key <-> value,value 1对多) 与 HttpServletRequest 进行同步等操作
    request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

    try { // 这个 doDispatch 是分发请求的入口
        doDispatch(request, response);
    }
    finally {
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            // Restore the original attribute snapshot, in case of an include.
            if (attributesSnapshot != null) { // 若是 include Request, 则恢复原先 HttpServletRequest 中的数据
                restoreAttributesAfterInclude(request, attributesSnapshot);              
            }
        }
    }
}

上面代码中主要是将请求必需的一些处理对象设置到 Request 里面, 而正真的请求是交给了 doDispatch 来处理, 主流程如下:

1. 通过 MultipartResolver 解析 HttpServletRequest, 主要是针对 Multi 请求进行一些数据解析操作
2. 遍历 HandlerMapping 查找能处理请求 HttpServletRequest 的 Handler, HandlerInterceptor, 最终封装成 HandlerExecutionChain
   2.1 若 2 中没找到 handler, 则在 Response 设置 404, 请求结束
3. 获取 Handler 对应的 HandlerAdapter (PS: 为增加 DispatcherServlet 的扩展性能, 增加了 HandlerAdapter, 所有的请求都通过 HandlerAdapter.handle 来进行处理)
4. 若请求时 GET|HEAD 请求, 则检查 Last-Modified, 若发现在缓存期内, 则直接返回 HttpCode = 304
5. 调用 HandlerExecutionChain.applyPreHandle 来激活拦截器的 handler前置方法, 若有返回 false, 则终止接下来的执行
6. 调用 HandlerAdapter.handle 来激活 handler 中的处理方法
7. 调用 HandlerExecutionChain.applyPostHandle 来激活拦截器的 handler后置方法
8. 调用 processDispatchResult 来将上诉操作的异常转换成 ModeAndView, 并进行 View 的渲染操作, 并输出到 client
9. 若上述操作中出现了异常, 则直接激活 HandlerInterceptor.afterCompletion 方法
10. 若是 multi 请求, 则清除请求中产生的数据

代码如下:

/**
 * 1. 所有的关于 http 协议的方法都是通过 本地方法来处理
 * 2. 处理过程中, handler 处理器是核心, 优先从 HandlerMapping 中获取, 再而可通过 handlerAdapter 适配器来再一层包装供支持更多形式的请求
 */
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    // mappedHandler 是处理核心, 此处可以理解为处理链
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;
    // 从 request 中获取 WebAsyncManager
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {
        // 这里为视图准备好一个 ModelAndView, 这个 ModelAndView 持有的handler处理请求的结果
        // 视图对象
        ModelAndView mv = null;
        // 异常对象
        Exception dispatchException = null;

        try {
            // 如果是 MultipartContent 类型的 request 则转换 request 为 MultipartHttpServletRequest 类型的 request
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request); // multipartRequestParsed 表示请求是否是 multi 类的请求
            // 根据请求得到对应的 handler, handler 的注册以及 getHandler 的实现
            // Determine handler for the current request. 优先从 HandlerMapping 中获取处理器对象
            mappedHandler = getHandler(processedRequest);
            // 这里找不到 handler 则会出现我们熟悉的 "no mapping found " 日志打印
            if (mappedHandler == null || mappedHandler.getHandler() == null) {
                // 如果没有找到 对应的 handler, 则通过 response 反馈错误信息, 返回 404 错误
                noHandlerFound(processedRequest, response);
                return;
            }

            // 根据当前的 Handler 寻找 对应的 HandlerAdapter, 通过 handlerAdapter.supports 方法
            // Determine handler adapter for the current request.
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // Process last-modified header, if supported by the handler.
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                // 如果当前 handler 支持 last-modified, 获取上次修改时间, 第一次访问为 -1L
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (logger.isDebugEnabled()) {
                    logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                }
                // 对未修改的资源 get 请求, 直接返回 304 状态码
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }
            // 拦截器处理请求, 调用拦截器接口 preHandler 方法, 一旦 HandlerInterceptor 返回 false, 则表示不需要进行下面 handler 进行处理
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }
            // 通过调用 HandlerAdapter 的handle方法 实际上触发 handler 的方法
            // Actually invoke the handler.
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }
            // 倘若 MV 对象内部没有逻辑视图名则采取默认视图, 默认视图名称的获取通过 HttpServletRequest
            applyDefaultViewName(processedRequest, mv);
            // 调用拦截器 HandlerInterceptor 接口的 posthandle 接口 (handler的后置处理器)
            mappedHandler.applyPostHandle(processedRequest, response, mv);
        }
        catch (Exception ex) {
            dispatchException = ex;
        }
        catch (Throwable err) {
            // 处理请求中出现了异常
            // As of 4.3, we're processing Errors thrown from handler methods as well,
            // making them available for @ExceptionHandler methods and other scenarios.
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }
        // 异常及视图处理, 如果有异常出现, 将异常转为对应的 ModelAndView, 接着就是 视图渲染
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
    catch (Exception ex) {
        // 调用请求拦截器 HandlerInterceptor 接口的 afterCompletion()方法
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    }
    catch (Throwable err) {
        // 调用请求拦截器 HandlerInterceptor 接口的 afterCompletion()方法
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                new NestedServletException("Handler processing failed", err));
    }
    finally {
        if (asyncManager.isConcurrentHandlingStarted()) { // 若异步处理已经开始
            // Instead of postHandle and afterCompletion
            if (mappedHandler != null) {
                // 调用所有的实现了 AsyncHandlerInterceptor 接口de afterConcurrentHandlingStared 方法
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        }
        else {
            // Clean up any resources used by a multipart request.
            if (multipartRequestParsed) {
                // 清除文件上传请求的相关信息, 释放资源
                cleanupMultipart(processedRequest);
            }
        }
    }
}

再回顾一下父类中做的事情, 可以将整个请求归纳为:

1. 请求准备, 构造数据, 数据主要设置到 HttpServletRequest, ThreadLocal 中
2. 进行请求参数的解析操作, 比如针对 multi 类请求
3. 通过请求映射 HandlerMapping 获取最终的请求处理方法 Handler 
4. 根据 Handler 来获取 HandlerAdapter (HandlerAdapter 定义请求的基本入口, 以此来适配不同类型的Handler )
5. Handler拦截器的前置方法调用, 其中只要有一个拦截器返回 false, 则终止请求
6. 通过 HandlerAdapter 来激活 Handler 方法来处理请求
7. Handler拦截器的后置方法调用
8. 进行统一异常处理, 并进行视图处理|渲染, 输出到客户端
9. 清除请求过程中产生的数据(PS: HttpServletRequest, ThreadLocal 中)
6. DispatcherServlet 中的优秀设计
1. 模板模式:      父类 FrameworkServlet 的processRequest中定义逻辑处理的主流程, 其中有一个抽象方法 doService(模板方法), 这里才是正真处理的地方, 留给FrameworkServlet的子类进行实现!
2. ThreadLocal:  通过ThreadLocal将程序中需要使用的变量, 以来解决变量并发安全的问题
3. 责任链模式:    准确的说是一个变种责任链, 体现在 HandlerExecutionChain, HandlerExecutionChain 中封装了要执行的拦截器, 最后是要激活的 Handler, 程序通过拦截器来控制程序的执行
4. 适配器模式:    这里适配器模式的存在是为了支持多种 Controller(有基于 @RequestMapping, 有实现 Controller接口的类), 具体体现在 HandlerAdapter 上
7. 总结

整个 SpringMVC 其实建立在 Spring IOC, AOP 之上(所以建在看 SpringMVC 源码时先把 IOC, AOP 弄清楚), 从上帝视角来看, 其实就是 DispatcherServlet 接受所有请求, 再通过 HandlerMapping 中获取对应的 handler, 通过 HandlerAdapter 来适配 Handler 的调用, 最后通过视图解析器来生成最终的视图, 接着写入到 Response!

8. 参考资料

SpringMVC源码分析系列
Spring MVC源码剖析
Spring源码情操陶冶
Spring 揭秘
Spring 技术内幕
Spring 源码深度分析
看透 Spring MVC 源代码分析与实践

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,688评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,559评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,749评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,581评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,741评论 3 271
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,684评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,122评论 2 292
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,847评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,441评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,939评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,333评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,783评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,275评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,830评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,444评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,553评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,618评论 2 249

推荐阅读更多精彩内容