zoukankan      html  css  js  c++  java
  • SpringMVC的工作流程及原理详解

    什么是SpringMVC?

    Spring MVC是一种基于Java的实现了MVC设计模式的、请求驱动类型的、轻量级Web框架。Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。SpringMVC是一种web层的mvc框架,用于替代servlet(处理响应请求,获取表单参数,表单验证等)。

    工作流程图

    我个人整理的详细流程图:

    工作流程详解

    1.由客户端发起请求,到达中央控制器,一般我们配置DispatcherServlet如下:

        <!-- Spring MVC servlet -->
        <servlet>
            <servlet-name>SpringMVC</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!--此参数可以不配置,默认值为:/WEB-INF/springmvc-servlet.xml-->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>/WEB-INF/spring-mvc.xml</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
            <!--web.xml 3.0的新特性,是否支持异步-->
            <async-supported>true</async-supported>
        </servlet>
        <servlet-mapping>
            <servlet-name>SpringMVC</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>

    2.中央控制器DispatcherServlet根据请求URI进行解析,找到相应的HandlerMapping(处理器映射器),而HandlerMapping是项目启动就保存在中央控制器中的集合内,我们可以通过源码看到:

     所有的属性都有自己的初始化init方法:

     3.DispatcherServlet通过HandlerMapping获取到相应的HandlerExecutionChain(一个执行链对象),发生在getHandler方法内部,未找到就返回空进入另外的操作:

        @Nullable
        protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
            if (this.handlerMappings != null) {
                Iterator var2 = this.handlerMappings.iterator();
    
                while(var2.hasNext()) {
                    HandlerMapping hm = (HandlerMapping)var2.next();
                    if (this.logger.isTraceEnabled()) {
                        this.logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + this.getServletName() + "'");
                    }
    
                    HandlerExecutionChain handler = hm.getHandler(request);
                    if (handler != null) {
                        return handler;
                    }
                }
            }
    
            return null;
        }

    4.然后中央控制器DispatcherServlet根据HandlerExecutionChain内的Handler(执行器)对象来匹配相应的HandlerAdapter(处理器适配器),这一步发生在getHandlerAdapter方法内:

        protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
            if (this.handlerAdapters != null) {
                Iterator var2 = this.handlerAdapters.iterator();
    
                while(var2.hasNext()) {
                    HandlerAdapter ha = (HandlerAdapter)var2.next();
                    if (this.logger.isTraceEnabled()) {
                        this.logger.trace("Testing handler adapter [" + ha + "]");
                    }
    
                    if (ha.supports(handler)) {
                        return ha;
                    }
                }
            }
    
            throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
        }

    5.适配器(HandlerAdapter)执行handle方法将HandlerExecutionChain内的执行器(Handler)运行(也就是我们写的Controller),并且返回一个ModelAndView模型视图对象:

    //mv就是上面定义的ModelAndView对象,mappedHandler就是上面说的HandlerExecutionChain对象
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

    6.中央控制器将接收到的ModelAndView对象进行检查,实际调用的是HandlerInterceptor(处理器拦截器)的postHandle方法:

    //注意这个方法是在HandlerExcutionChain类中,调用applyPostHandle检查视图是否存有异常
    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
            HandlerInterceptor[] interceptors = this.getInterceptors();
            if (!ObjectUtils.isEmpty(interceptors)) {
                for(int i = interceptors.length - 1; i >= 0; --i) {
                    HandlerInterceptor interceptor = interceptors[i];
                    interceptor.postHandle(request, response, this.handler, mv);
                }
            }
    
        }

    7.上一步没有异常进入视图解析工作,中央控制器将ModelAndView交给视图解析器(View)进行解析(拼接路径,指向视图),并且返回一个真正的View也就是我们的页面。

    8.中央控制器接收到View进行数据渲染,填充数据,这两步发生在processDispatchResult方法内:

        private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
            boolean errorView = false;
            if (exception != null) {
                if (exception instanceof ModelAndViewDefiningException) {
                    this.logger.debug("ModelAndViewDefiningException encountered", exception);
                    mv = ((ModelAndViewDefiningException)exception).getModelAndView();
                } else {
                    Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
                    mv = this.processHandlerException(request, response, handler, exception);
                    errorView = mv != null;
                }
            }
    
            if (mv != null && !mv.wasCleared()) {
                this.render(mv, request, response);
                if (errorView) {
                    WebUtils.clearErrorRequestAttributes(request);
                }
            } else if (this.logger.isDebugEnabled()) {
                this.logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + this.getServletName() + "': assuming HandlerAdapter completed request handling");
            }
    
            if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
                }
    
            }
        }

    9.如果是并发处理,则进行最后的检查,最终响应到客户端,完成一次请求响应。

        void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception {
            HandlerInterceptor[] interceptors = this.getInterceptors();
            if (!ObjectUtils.isEmpty(interceptors)) {
                for(int i = this.interceptorIndex; i >= 0; --i) {
                    HandlerInterceptor interceptor = interceptors[i];
    
                    try {
                        interceptor.afterCompletion(request, response, this.handler, ex);
                    } catch (Throwable var8) {
                        logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
                    }
                }
            }
    
        }

    DispatcherServlet主要操作都发生在doDispatch方法内部:

        protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
            HttpServletRequest processedRequest = request;//request
            HandlerExecutionChain mappedHandler = null;//执行链
            boolean multipartRequestParsed = false;//验证是否文件流请求
            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);//异步请求管理器
    
            try {
                try {
                    ModelAndView mv = null;//模型视图
                    Object dispatchException = null;
    
                    try {
                        processedRequest = this.checkMultipart(request);//检查是否文件上传相关
                        multipartRequestParsed = processedRequest != request;//验证请求对象
                        mappedHandler = this.getHandler(processedRequest);//获取执行链
                        if (mappedHandler == null) {
                            this.noHandlerFound(processedRequest, response);
                            return;
                        }
    
                        HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());//根据执行链中的Handler对象获取对应的适配器
                        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;
                            }
                        }
    
                        if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                            return;
                        }
    
                        mv = ha.handle(processedRequest, response, mappedHandler.getHandler());//执行Handler返回模型视图,也就是我们的Controller
                        if (asyncManager.isConcurrentHandlingStarted()) {
                            return;
                        }
    
                        this.applyDefaultViewName(processedRequest, mv);//补充逻辑视图名
                        mappedHandler.applyPostHandle(processedRequest, response, mv);//执行拦截器的postHandle方法
                    } catch (Exception var20) {
                        dispatchException = var20;
                    } catch (Throwable var21) {
                        dispatchException = new NestedServletException("Handler dispatch failed", var21);
                    }
    
                    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);
                }
    
            }
        }    

    重要组件功能

    1. 前端控制器(DispatcherServlet):接收请求,响应结果,相当于转发器,调度其他组件、分发任务,中央处理器
    2. 请求到处理器映射(HandlerMapping):根据请求的url查找Handler
    3. 处理器适配器(HandlerAdapter):按照特定规则(HandlerAdapter要求的规则)去执行Handler
    4. 视图解析器(ViewResolver):进行视图解析,根据逻辑视图名解析成真正的视图(view)
    5. 处理器或页面控制器(Handler):执行具体的用户请求,也就是我们的业务Controller
    6. 验证器(Validator):验证数据安全
    7. 命令对象(command object):请求参数绑定到的对象就叫命令对象
    8. 表单对象(form object):请求表单数据对象

    SpringMVC特点

    • 清晰的角色划分:控制器(controller)、验证器(validator)、 命令对象(command object)、表单对象(formobject)、模型对象(model object)、 Servlet分发器(DispatcherServlet)、处理器映射(handler mapping)、视图解析器(view resolver)等。每一个角色都可以由一个专门的对象来实现。
    • 强大而直接的配置方式:将框架类和应用程序类都能作为JavaBean配置,支持跨多个context的引用,例如,在web控制器中对业务对象和验证器(validator)的引用。
    • 可适配、非侵入:可以根据不同的应用场景,选择合适的控制器子类 (simple型、command型、form型、wizard型、multi-action型或者自定义),而不是从单一控制器 (比如Action/ActionForm)继承。
    • 可重用的业务代码:可以使用现有的业务对象作为命令或表单对象,而不需要去扩展某个特定框架的基类。
    • 可定制的绑定(binding) 和验证(validation):比如将类型不匹配作为应用级的验证错误, 这可以保存错误的值。再比如本地化的日期和数字绑定等等。在其他某些框架中,你只能使用字符串表单对象,需要手动解析它并转换到业务对象。
    • 可定制的handlermapping和view resolution:Spring提供从最简单的URL映射, 到复杂的、专用的定制策略。与某些webMVC框架强制开发人员使用单一特定技术相比,Spring显得更加灵活。
    • 灵活的model转换:在Springweb框架中,使用基于Map的 键/值对来达到轻易地与各种视图技术的集成。
    • 可定制的本地化和主题(theme)解析:支持在JSP中可选择地使用Spring标签库、支持JSTL、支持Velocity(不需要额外的中间层)等等。
    • 简单而强大的JSP标签库(SpringTag Library):支持包括诸如数据绑定和主题(theme) 之类的许多功能。
    • JSP表单标签库:在Spring2.0中引入的表单标签库,使得在JSP中编写 表单更加容易。
    • Spring Bean的生命周期可以被限制在当前的HTTP Request或者HTTP Session。
  • 相关阅读:
    https://github.com/apache/tomcat.git
    Tomcat 7最大并发连接数的正确修改方法
    如何解决svn Authorization failed错误
    Centos7下Rinetd安装与应用
    [原创]CI持续集成系统环境--Gitlab+Gerrit+Jenkins完整对接https://www.cnblogs.com/kevingrace/p/5651447.html
    git branch --set-upstream hmyq/master master
    git clone,push,pull,fetch命令详解
    差异:git clone , git fetch, git pull和git rebase
    CENTOS6.6下mysql5.7.11的percona-xtrabackup安装与备份
    Docker报错“Dockerfile parse error line 1: FROM requires either one or three arguments”
  • 原文地址:https://www.cnblogs.com/StarChen20/p/13995258.html
Copyright © 2011-2022 走看看