SpringMVC学习——概念、流程图、源码简析(一)

  学习资料:开涛的《跟我学SpringMVC.pdf》

  众所周知,springMVC是比较常用的web框架,通常整合spring使用。这里抛开spring,单纯的对springMVC做一下总结。

  概念

  HandlerMapping:处理器映射,对请求的URL进行映射为具体的处理器(如果有拦截器也包含拦截器,会将Handler和多个HandlerInterceptor封装为HandlerExecutionChain对象)

  HandlerAdapter:处理器适配器,适配不同类型的处理器,如Controller、AbstractController等

  Handler:处理器,即开发的Controller

  ModeAndView:模型和视图,未来会渲染为具体的视图

  ViewResolver:视图解析器,将逻辑视图名称转化为物理视图

  View:视图

  流程图

  源码简析(摘自DispatcherServlet源码部分)

  由于springMVC的配置本身就上一个servlet,所以跟踪代码doService()=>doDispatcher(),核心代码如下所示,中文注释自己加的:

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

        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

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

            try {
                //对文件上传类型的数据进行处理,使用MultipartResolver解析
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);

                //使用HandlerMapping进行映射,将一个Handler和多个HandlerInterceptor封装为HandlerExecutionChain对象
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }

                //根据Handler获取合适的Handler适配器
                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)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        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;
                }

                //使用HandlerAdapter执行Handler并返回ModeAndView
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }

                applyDefaultViewName(processedRequest, mv);
                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);
            }
            //处理转发结果,包含ModeAndView的视图解析
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
            triggerAfterCompletion(processedRequest, response, mappedHandler,
                    new NestedServletException("Handler processing failed", err));
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                // Instead of postHandle and afterCompletion
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                // Clean up any resources used by a multipart request.
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }
时间: 2024-10-12 18:30:23

SpringMVC学习——概念、流程图、源码简析(一)的相关文章

并发工具-CyclicBarrier源码简析

CyclicBarrier是循环栅栏的意思,循环的等待多个线程执行任务: <1> 示例代码如下: public class CyclicBarrierTest { public static CyclicBarrier cb = new CyclicBarrier(3, () -> System.out.println("-------开始点名-------")); public static void main(String[] args) { System.out

0002 - Spring MVC 拦截器源码简析:拦截器加载与执行

1.概述 Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理.例如通过拦截器可以进行权限验证.记录请求信息的日志.判断用户是否登录等. 2.简单示例 2.1.继承 HandlerInterceptorAdapter 抽象类实现一个拦截器.代码如下: public class DemoInterceptor extends HandlerInterceptorAdapter { @Override    pu

JDK源码简析--java.lang包中的基础类库

题记 JDK,Java Development Kit. 我们必须先认识到,JDK只是,仅仅是一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含量来说,还是在一个层级上,它们都是需要被编译成字节码,在JRE中运行的,JDK编译后的结果就是jre/lib下得rt.jar,我们学习使用它的目的是加深对Java的理解,提高我们的Java编码水平. 本系列所有文章基于的JDK版本都是1.7.16. 本节内容 在本节中,简析java.lang包所包

JDK源码简析--java.util包中的工具类库

题记 JDK,Java Development Kit. 我们必须先认识到,JDK只是,仅仅是一套Java基础类库而已,是Sun公司开发的基础类库,仅此而已,JDK本身和我们自行书写总结的类库,从技术含量来说,还是在一个层级上,它们都是需要被编译成字节码,在JRE中运行的,JDK编译后的结果就是jre/lib下得rt.jar,我们学习使用它的目的是加深对Java的理解,提高我们的Java编码水平. 本系列所有文章基于的JDK版本都是1.7.16. 本节内容 在本节中,简析java.util包所包

Linux Hugetlbfs内核源码简析-----(一)Hugetlbfs初始化

一.引言 为了实现虚拟内存管理机制,操作系统对内存实行分页管理.自内存“分页机制”提出之始,内存页面的默认大小便被设置为 4096 字节(4KB),虽然原则上内存页面大小是可配置的,但绝大多数的操作系统实现中仍然采用默认的 4KB 页面.当某些应用的需要使用的内存达到几G.甚至几十G的时候,4KB的内存页面将严重制约程序的性能. CPU缓存中有一组缓存专门用于缓存TLB,但其大小是有限的.当采用的默认页面大小为 4KB,其产生的TLB较大,因而将会产生较多 TLB Miss 和缺页中断,从而大大

[tomcat]源码简析 异步/非阻塞和请求构成

提出疑惑 SpringFramework5.0又新增加了一个功能Webflux(响应式编程),是一个典型非阻塞异步的框架.我们知道servlet3.0实现异步(AsyncContext),servlet3.1又提出了非阻塞IO.对此我一直有两点疑惑:1.tomcat8底层已经默认使用NIO了,不是已经是IO非阻塞了吗,怎么又说servlet3.1解决了非阻塞.2.关于异步,如果开发者在serlvet中开一个业务线程来实现,也算异步,为什么3.0还提供了一个组件来解决,那么这种方式和开发者自己开个

第五节:JQuery框架源码简析(1)

(转自老惠的博客) JQuery是一个应用广泛.非常优秀的JavaScript框架,其代码简洁而优雅,有很多值得我们学习的地方.这里仅仅对其代码结构做一个简单的分析,方便大家的理解和学习. 我们进行分析.分解的基准版本是jQuery1.7.1. 开始之前,请准备好以下素材和工具: jQuery源代码:jquery-1.7.1.js 文本编辑器:EditPlus,或者你喜欢的 参考书:<jQuery高级编程>.<jQuery技术内幕:深入解析jQuery架构设计与实现原理>.<

ReentrantLock源码简析

概念 ReentrantLock,可重入锁.在多线程中,可以通过加锁保证线程安全. ReentrantLock,是基于AQS实现的. 加锁和解锁 加锁: public void lock() { sync.lock(); } 解锁 public void unlock() { sync.release(1); } 内部类Sync继承AQS,因此可以维护状态变量state,通过acquire()获取state.release()释放state.后文会涉及. 构造方法 无参构造方法 默认使用非公平锁

Android -- Camera源码简析,启动流程

com.android.camera.Camera.java,主要的实现Activity,继承于ActivityBase. ActivityBase 在ActivityBase中执行流程: onCreate中进行判断是否是平板: onResume中判断是否锁屏,锁屏&camera不存在时候,mOnResumePending置为true,否则置为false并执行doOnResume: onWindowFocusChanged中判断是否获取到焦点&mOnResumePending,满足的话执行