• 04.SpringMVC之用


    分析 Spring MVC 是怎么处理请求的。首先分析 HttpServletBean、FrameworkServlet 和 DispatcherServlet 这三个 Servlet 的处理过程,最后分析 doDispatcher 的结构。

    HttpServletBean

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

    FrameworkServlet

    在类中的 service() 、doGet()、doPost()、doPut()、doDelete()、doOptions()、doTrace() 这些方法中可以看到都调用了一个共同的方法 processRequest() ,它是类在处理请求中最核心的方法。

    protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            long startTime = System.currentTimeMillis();
            Throwable failureCause = null;
            //获取 LocaleContextHolder 中原来保存的 LocaleContext
            LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
            //获取当前请求的 LocaleContext
            LocaleContext localeContext = buildLocaleContext(request);
            //获取 RequestContextHolder 中原来保存的 RequestAttributes
            RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
            //获取当前请求的 ServletRequestAttributes
            ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
    
            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
            asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
    //将当前请求的 LocaleContext 和 ServletRequestAttributes 设置到 LocaleContextHolder 和 RequestContextHolder
            initContextHolders(request, localeContext, requestAttributes);
    
            try {
                //实际处理请求的入口,这是一个模板方法,在 Dispatcher 类中才有具体实现
                doService(request, response);
            }catch (ServletException ex) {
                failureCause = ex;
                throw ex;
            }catch (IOException ex) {
                failureCause = ex;
                throw ex;
            }catch (Throwable ex) {
                failureCause = ex;
                throw new NestedServletException("Request processing failed", ex);
            }finally {
                //将 previousLocaleContext,previousAttributes 恢复到 LocaleContextHolder 和 RequestContextHolder 中
                resetContextHolders(request, previousLocaleContext, previousAttributes);
                if (requestAttributes != null) {
                    requestAttributes.requestCompleted();
                }
                //删除了日志打印代码
                //发布了一个 ServletRequestHandledEvent 类型的消息
                publishRequestHandledEvent(request, response, startTime, failureCause);
            }
        }

    DispatcherServlet

    上一章中其实还没把该类讲清楚,在这个类中,里面的智行处理的入口方法应该是 doService 方法,方法里面调用了 doDispatch 进行具体的处理,在调用 doDispatch 方法之前 doService 做了一些事情:首先判断是不是 include 请求,如果是则对 request 的 Attribute 做个快照备份,等 doDispatcher 处理完之后(如果不是异步调用且未完成)进行还原 ,在做完快照后又对 request 设置了一些属性。

    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;
            if (WebUtils.isIncludeRequest(request)) {
                attributesSnapshot = new HashMap<>();
                Enumeration<?> attrNames = request.getAttributeNames();
                while (attrNames.hasMoreElements()) {
                    String attrName = (String) attrNames.nextElement();
                    if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)){
                        attributesSnapshot.put(attrName, request.getAttribute(attrName));
                    }
                }
            }
            // Make framework objects available to handlers and view objects.
            request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
            request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
            request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
            request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
    
            FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
            if (inputFlashMap != null) {
                request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
            }
            request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
            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) {
                        restoreAttributesAfterInclude(request, attributesSnapshot);
                    }
                }
            }
        }

    doDispatch() 方法:

    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 {
                    //检查是不是上传请求
                    processedRequest = checkMultipart(request);
                    multipartRequestParsed = (processedRequest != request);
    
                    // Determine handler for the current request.  根据 request 找到 Handler
                    mappedHandler = getHandler(processedRequest);
                    if (mappedHandler == null || mappedHandler.getHandler() == null) {
                        noHandlerFound(processedRequest, response);
                        return;
                    }
    
        // Determine handler adapter for the current request.根据 Handler 找到对应的 HandlerAdapter
                    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
                    // Process last-modified header, if supported by the handler.
                    //处理 GET 、 HEAD 请求的 LastModified
                    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;
                        }
                    }
                    //执行相应的 Interceptor 的 preHandle
                    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                        return;
                    }
                    // Actually invoke the handler. HandlerAdapter 使用 Handler 处理请求
                    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                    //如果需要异步处理,直接返回
                    if (asyncManager.isConcurrentHandlingStarted()) {
                        return;
                    }
                    //当 view 为空时,根据 request 设置默认 view
                    applyDefaultViewName(processedRequest, mv);
                    //执行相应 Interceptor 的 postHandler
                    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);
                }
                //调用 processDispatchResult 方法处理上面处理之后的结果(包括处理异常,渲染页面,发出完成通知触发 Interceptor 的 afterCompletion)
                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);
                    }
                }
            }
        }

    Handler,HandlerMapping,HandlerAdapter 三个区别:

    • Handler:处理器,对应 MVC 的 C层,也就是 Controller 层,具体表现形式有很多种,可以是类,方法,它的类型是 Object,只要可以处理实际请求就可以是 Handler。

    • HandlerMapping:用来查找 Handler 的。

    • HandlerAdapter :Handler 适配器,

    另外 View 和 ViewResolver 的原理与 Handler 和 HandlerMapping 的原理类似。

  • 相关阅读:
    16个能帮你找到网页设计灵感的网站
    Charts 图表插件
    jquery获取text,areatext,radio,checkbox,select值(转)
    原型开发、模型构建和设计反馈在线工具
    AutoComplete 自动完成插件(2)
    以蓝色为主题的网站设计灵感
    25个必须要学会的jQuery幻灯片插件教程(中)
    25个必须要学会的jQuery幻灯片插件教程(上)
    极具创意和趣味性的网站404错误页面设计集合
    用CSS制作横向菜单
  • 原文地址:https://www.cnblogs.com/deityjian/p/11494557.html
Copyright © 2020-2023  润新知