zoukankan      html  css  js  c++  java
  • SpringMVC处理请求

    HttpServletBean

    HttpServletBean主要参与了创建工作,并没有涉及请求的处理。

    FrameworkServlet

    FrameworkServlet的service方法里添加了对PATCH的处理,并将所有需要自己处理的请求都集中到了processRequest方法进行统一处理,这和HttpServlet里面根据request的类型将请求分配到各个不同的方法进行处理的过程正好相反。
    processRequest方法里主要的处理逻辑交给了doService,这是一个模板方法,在子类DispatcherServlet实现。

    DispatcherServlet

    DispatcherServlet的doServic并没有直接进行处理,而是交给了doDispatch进行具体的处理;在doDispatch处理前doServic做了一些事情,判断是不是include请求,如果是则对request的Attribute做个快照备份,等doDispatch处理完之后进行还原。

    doDispatch的核心代码
    // 根据request找到Handler
    mappedHandler = getHandler(processedRequest);
    // 根据Handler找到对应的HandlerAdapter
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    // 用HandlerAdapter处理Handler
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    // 处理上面的结果,包含找到View并渲染输出给用户
    processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

    Handler:处理器,对应MVC中的Controller层,它可以是类,也可以是方法;标注了@RequestMapping的方法就是一个Handler。
    HandlerMapping:用来查找Handler
    HandlerAdapter:Spring MVC中的Handler可以是任意的形式,只要能处理请求就OK,但是Servlet需要的处理方法的结构却是固定的,都是以request和response为参数的方法。HandlerAdapter让固定的Servlet处理方法可以调用灵活的Handler来处理请求。

    源码分析:

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 请求对象,如果是上传请求会封装为上传类型的request
        HttpServletRequest processedRequest = request;
        // 处理器链,包含处理器和Interceptor
        HandlerExecutionChain mappedHandler = null;
        // 是不是文件上传
        boolean multipartRequestParsed = false;
        // 异步管理
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    
        try {
            try {
                ModelAndView mv = null;
                // 异常对象
                Object dispatchException = null;
                try {    
                    //如果是上传请求,将request转换为MultipartHttpServletRequest,用到了MultipartResolver
                    processedRequest = this.checkMultipart(request);
                    multipartRequestParsed = processedRequest != request;
                    // 根据request找到处理器链,其中包含与当前request相匹配的Interceptor和handler
                    // Interceptor和Handler,执行时先调用Interceptor的preHandle方法,最后执行Handler
                    // 返回的时候按相反的顺序执行Interceptor的postHandle方法
                    mappedHandler = this.getHandler(processedRequest);
                    if (mappedHandler == null || mappedHandler.getHandler() == null) {
                        this.noHandlerFound(processedRequest, response);
                        return;
                    }
                    // 根据Handler找到对应的HandlerAdapter
                    HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
                    /* 处理Get、Head请求的LastModified
                     * 当浏览器第一次跟服务器请求资源(GET、Head请求)时,
                     * 服务器在返回的请求头里面会包含一个Last-Modified的属性,
                     * 代表本资源最后是什么时候修改的。
                     * 在浏览器以后发送请求时会同时发送之前接收到的LastModified,
                     * 服务器接收到带Last-Modified的请求后会用其值和自己实际资源的最后修改时间做对比,
                     * 如果资源过期了则返回新的资源(同时返回新的Last-Modified),
                     * 否则直接返回304状态码表示资源未过期,浏览器直接使用之前缓存的结果。
                     */
                    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;
                        }
                    }
                    /* 接下来依次调用相应Interceptor的preHandle、
                     * HandlerAdapter使用Handler处理请求,Controller就是在这个地方执行的,
                     * Handler处理完请求后,如果需要异步处理,则直接返回,
                     * 如果不需要异步处理,当view为空时(如Handler返回值为void),
                     * 设置默认view,然后执行相应Interceptor的postHandle。
                     */ 
                    // 执行相应的Interceptor的preHandle 
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
                    // HandlerAdapter使用Handler处理请求
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    // 如果需要异步处理直接返回
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
                    // 当view为空时,比如,Handler返回值为void,根据request设置默认的view
                    this.applyDefaultViewName(processedRequest, mv);
                    // 执行相应Interceptor的方法
                    mappedHandler.applyPostHandle(processedRequest, response, mv);
                } catch (Exception var20) {
                    dispatchException = var20;
                } catch (Throwable var21) {
                    dispatchException = new NestedServletException("Handler dispatch failed", var21);
                }
                // 处理返回结果。包括处理异常、渲染页面、发出完成通知触发Interceptor的afterCompletion
                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);
            }
    
        }
    }
  • 相关阅读:
    不懂不可耻,可耻的是每当遇到不懂的东西不是想办法去学去了解而是极力掩饰。
    在咱学校的论坛上看到的一句话,觉得……我们都在等待某个人,等到累了,就随便牵起某人的手,默默地走进礼...
    在Linux下用Virtualbox虚拟机安装Windows XP
    大学里的挂科是对考前三天不用功的惩罚.这是教算法的赵PZ讲的,窃以为很有道理。可是接下来的十一天里我...
    壮哥!才发现你博客里这么多好东西,慢慢欣赏了,哈哈~~~~~~~~~~
    哥们现在用的什么?ghs不是又被封了吗
    提取字符串中的数字并分别保存
    十一天八考之路
    WPF使ListBox支持手势多选功能
    动手实现扩展属性为对象动态添加获取数据(续)
  • 原文地址:https://www.cnblogs.com/Mike_Chang/p/10498072.html
Copyright © 2011-2022 走看看