04.SpringMVC之用

Posted deityjian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 的原理类似。

以上是关于04.SpringMVC之用的主要内容,如果未能解决你的问题,请参考以下文章

阶段3 3.SpringMVC·_04.SpringMVC返回值类型及响应数据类型_1 搭建环境

阶段3 3.SpringMVC·_04.SpringMVC返回值类型及响应数据类型_4 响应之返回值是ModelAndView类型

Springday04 SpringMVC入门案例控制器和三大主件Spring请求参数绑定SpringMVC使用servlet的api请求头请求体相关注解

阶段3 3.SpringMVC·_04.SpringMVC返回值类型及响应数据类型_5 响应之使用forward和redirect进行页面跳转

阶段3 3.SpringMVC·_04.SpringMVC返回值类型及响应数据类型_2 响应之返回值是String类型

图文详解:docker部署nacos和redis