zoukankan      html  css  js  c++  java
  • SpringMVC的流程分析(一)—— 整体流程概括

    SpringMVC的整体概括

    之前也写过springmvc的流程分析,只是当时理解的还不透彻所以那篇文章就放弃了,现在比之前好了些,想着写下来分享下,也能增强记忆,也希望可以帮助到别人,如果文章中有什么错误的地方欢迎各位指出。(本文针对有一定的springmvc使用经验的it人员)。

    1.springmvc存在的意义

      任何一个框架都有其存在的价值,可以或多或少帮助我们解决一个繁琐的问题,springmvc也不例外,说白了其实他也没啥了不起,他就是个彻头彻尾的Servlet,

    一个封装许多任务的servlet,正是这些封装我们才感觉不到他单单是个servlet,因为他太厉害了,每个人在使用的时候应该都有过配置web.xml的经验,其中可以清晰的看到springmvc的配置,如下:

     <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>/WEB-INF/classes/spring/spring-servlet.xml</param-value>
        </init-param>
     </servlet>
      <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
      </servlet-mapping>

      我们可以看到springmvc的配置就是一个servlet的配置,对所有的url进行拦截。所以我们可以总结springmvc的作用:作为一个总的servlet对客户端的请求进行分发,然后对不同的请求处理,并返回相应的数据。

    2.springmvc的设计类图

    3.springmvc的入口

      上图中黄色标识的DispatcherServlet就是sprigmvc请求的核心入口类,可以看到这类通过FrameworkServelt间接继承了HttpServletBean,FrameworkServelt实现了ApplicationContextAware,用来设置springmvc的全局上下文,当客户发送请求时会先进入DispatcherServlet的doService方法:

      

    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
      
           //省略不重要代码。。。
            try {
                this.doDispatch(request, response);
            } finally {
                if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot1 != null) {
                    this.restoreAttributesAfterInclude(request, attributesSnapshot1);
                }
            }
    
        }

       其实是调用了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 {
                try {
                    ModelAndView err = null;
                    Exception dispatchException = null;
    
                    try {
                        processedRequest = this.checkMultipart(request);
                        multipartRequestParsed = processedRequest != request;
                        mappedHandler = this.getHandler(processedRequest);
                        if (mappedHandler == null || mappedHandler.getHandler() == null) {
                            this.noHandlerFound(processedRequest, response);
                            return;
                        }
    
                        HandlerAdapter ex = this.getHandlerAdapter(mappedHandler.getHandler());
                        String method = request.getMethod();
                        boolean isGet = "GET".equals(method);
                        if (isGet || "HEAD".equals(method)) {
                            long lastModified = ex.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;
                        }
    
                        err = ex.handle(processedRequest, response, mappedHandler.getHandler());
                        if (asyncManager.isConcurrentHandlingStarted()) {
                            return;
                        }
    
                        this.applyDefaultViewName(request, err);
                        mappedHandler.applyPostHandle(processedRequest, response, err);
                    } catch (Exception arg18) {
                        dispatchException = arg18;
                    }
    
                    this.processDispatchResult(processedRequest, response, mappedHandler, err, dispatchException);
                } catch (Exception arg19) {
                    this.triggerAfterCompletion(processedRequest, response, mappedHandler, arg19);
                } catch (Error arg20) {
                    this.triggerAfterCompletionWithError(processedRequest, response, mappedHandler, arg20);
                }
    
            } finally {
                if (asyncManager.isConcurrentHandlingStarted()) {
                    if (mappedHandler != null) {
                        mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                    }
                } else if (multipartRequestParsed) {
                    this.cleanupMultipart(processedRequest);
                }
           
            }
        }

    首先一上来是检查是否是文件上传请求,(这个检查的目的是为了在finally中清除文件上传相应的信息),然后就是获取handler

      mappedHandler = this.getHandler(processedRequest);

      什么是handler呢?其实handler是springmvc自己定义的一个处理具体请求的不同类的总称,我们知道客户端的请求有很多类型,例如静态资源的请求,动态资源的请求,restful风格的请求,也可能有原始servlet类型的请求,这些处理类的总称就是handler,具体如何得到handler我会另起一个章节讲解。好了,得到了hander(处理请求类)后我们是不是可以直接来处理请求了呢,就像这样:
      handler.methodname(request,response);
    其实还真是这样,哈哈,肯定是这样的呀,不过人家springmvc的设计者比咱们高明多了,才不会这么lou的写,好了,我们看看他们是怎么高明的吧:

      HandlerAdapter ex = this.getHandlerAdapter(mappedHandler.getHandler());

      HandlerAdapter?这是什么鬼呀,怎么得到了handler怎么还在得到HandlerAdapter呢,其实这就是人家的高明之处了,这里使用了适配器设计模式,每一种handler都会有一个对应的适配器,这样子我们就不用每次都判断handler的类型,然后调用不同的方法了,举个例子:

    class Handler1{
      Object handle1(HttpRequest request,HttpResponse response){
        
      }
    }
    class Handler2{
      Object handle2(HttpRequest request,HttpResponse response){
        
      }
    }
    class Handler3{
      Object handle3(HttpRequest request,HttpResponse response){
        
      }
    }

    这里有3个处理类,正常我们的调用是这样的:  

    if (handle instanceof Handler1) {
      handle.handle1();
    }
    if (handle instanceof Handler2) {
      handle.handle2();
    }
    if (handle instanceof Handler3) {
      handle.handle3();
    }

      如果我们此时又多了一个Handler4怎么办,难道们需要更改Springmvc的源代码吗,这显然不符合代码设计的开闭原则,适配器模式就是解决这个问题的最好方式每一个处理器都要有一个对应的适配器,这样我们就可以不用更改源代码也能添加handler了。
      接下来我们看到

     err = ex.handle(processedRequest, response, mappedHandler.getHandler());

      这个方法是请求的最终执行,不同类型的handler会有不同的实现,当处理器处理完各自的逻辑后都会放回一个ModelAndView参数,ModelAndView是springmvc对处理器返回的结果的抽象,不论处理器实际返回的是什么,Springmvc都会讲他包装成为ModelAndView,然后对ModelAndView进行处理,这里很有意思,也给我们一种启发,如果我们会得到很多不同的结果,我们可以将它抽象为一个统一的类型数据,然后针对这个类型的数据进行统一的处理,这样我们就可以不用针对每种情况后处理了。
      最后,Spingmvc会对ModelAndView进行处理,然后返回给浏览器。

     this.processDispatchResult(processedRequest, response, mappedHandler, err, dispatchException);

    上面这个方法就是对ModelAndView的处理。至此,springmvc的大体流程就结束了。以上只是我对springmvc的一个整体概述,之后我还会讲解Springmvc的Handler,HandlerAdapter,视图处理,拦截器,异常处理等内容。









  • 相关阅读:
    hdu 4333 扩展kmp
    扩展KMP
    hdu 1026 bfs+记录路径
    2015-04-26 校赛总结
    hdu 1514 记忆化搜索
    hdu 1208 记忆化搜索
    hdu 2266 dfs
    hdu 1518 dfs+剪枝
    android:layout_gravity和android:gravity的区别
    深圳市住房公积金提取办法
  • 原文地址:https://www.cnblogs.com/zcmzex/p/7738027.html
Copyright © 2011-2022 走看看