zoukankan      html  css  js  c++  java
  • SpringMVC运行流程源码分析

    springMVC的核心:DispatchServlet; 请求转发器,前端控制器
    <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--DispatchServlet可以绑定spring的配置文件-->
    <init-param>
    <!-- 指定SpringMVC配置文件位置 -->
    <param-name>contextConfigLocation</param-name>
    <!--如果不指定 默认 /WEB-INF/上面的名字-servlet.xml-->
    <param-value>classpath:spring-servlet.xml</param-value>
    </init-param>
    <!--启动级别1: 跟服务器一起启动-->
    <load-on-startup>1</load-on-startup>
    </servlet>
    <!--
    所有请求都会被springmvc拦截
    在springMVC中,/ 和 /*的区别
    / : 只匹配所有的请求,不会去匹配jsp页面
    /* : 匹配所有的请求,也会匹配jsp页面
    -->
    <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
    </servlet-mapping>

    DispatchServlet 是一个Servlet 继承关系图如下

    doDispatch是SpringMVC的核心类DispatcherServlet中的核心方法,源码如下
    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. 
             // 根据当前的请求地址找到能处理这个请求的目标处理器类(控制类) 也就是我们写的Controller类,用@Controller注解标注的类。
    mappedHandler = getHandler(processedRequest);

              
    // 如果没有相应的处理器/控制器,则抛出一个异常或者404; if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // 拿到能执行这个类的所有方法的适配器;
           // 根据当前处理器类获取到能执行这个处理器方法的适配器 如果使用的是注解@Controller,则就是AnnotationMethodHandlerAdapter适配器
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. 使用适配器执行目标方法 并返回一个ModelAndView对象。 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); 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(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); } } } }

    下面介绍
    doDispatch()里几个重要方法    
      1、getHandler() 根据当前请求在HandlerMapping中找到这个请求的映射信息,获取到目标处理器类
    @Nullable
        protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
          // handlerMapping存储了所有的请求的Handler,包括注解的和配置的,遍历所有的请求,找到符合当前请求的handler 如果不为空,直接返回
    if (this.handlerMappings != null) { for (HandlerMapping mapping : this.handlerMappings) { HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; }
       2、getHandlerAdapter() 根据当前处理器类,找到当前类的HandlerAdapter(适配器)
    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
         // 遍历所有的适配器,包括
    AbstractHandlerMethodAdapter(由RequestMappingHandlerAdapter继承,正常注解拿到的就是这个适配器)
        // HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、SimpleServletHandlerAdapter
    if (this.handlerAdapters != null) { 
      for (HandlerAdapter adapter : this.handlerAdapters) {
          // 判断当前适配器是否是请求所需要的适配器,多数是用的instance of来进行判断
        
    if (adapter.supports(handler)) {
              return adapter;
          }
        }
      }
    throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }

        3、mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  执行目标方法  最难的一步  主要看看目标方法在何时,在哪执行的

          正常注解类的请求会走 RequestMappingHandlerAdapter类下的 handleInternal() 方法

          该方法核心一步就是

    mav = invokeHandlerMethod(request, response, handlerMethod);

          该方法中的核心方法  invocableMethod.invokeAndHandle(webRequest, mavContainer);

          接着进入这个方法  Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);  这个方法用来invoke请求

          进入这个方法

    @Nullable
        public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
                Object... providedArgs) throws Exception {
          // 设置所有目标方法参数  进入这个方法你可以看到,该方法申请了一个长度跟目标参数个数相等的Object数组,并把目标参数放入放入数组中 然后返回该数组
            Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
            if (logger.isTraceEnabled()) {
                logger.trace("Arguments: " + Arrays.toString(args));
            }
          // 执行目标方法
    return doInvoke(args); }

          进入doInvoke方法

    @Nullable
        protected Object doInvoke(Object... args) throws Exception {
            ReflectionUtils.makeAccessible(getBridgedMethod());
            try {
           // 终于在这里 SpringMVC调用了反射底层的invoke方法 目标方法得以执行
    return getBridgedMethod().invoke(getBean(), args); } catch (IllegalArgumentException ex) { assertTargetBean(getBridgedMethod(), getBean(), args); String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument"); throw new IllegalStateException(formatInvokeError(text, args), ex); } catch (InvocationTargetException ex) { // Unwrap for HandlerExceptionResolvers ... Throwable targetException = ex.getTargetException(); if (targetException instanceof RuntimeException) { throw (RuntimeException) targetException; } else if (targetException instanceof Error) { throw (Error) targetException; } else if (targetException instanceof Exception) { throw (Exception) targetException; } else { throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException); } } }

    SpringMVC九大组件

      SpringMVC在工作的时候,关键位置都是由组件完成的;

      这九大组件的共同点就是:全都是接口;接口就是规范,提供了非常强大的扩展性

    /** 文件上传解析器 */
        @Nullable
        private MultipartResolver multipartResolver;
    
        /** 区域信息解析器:和国际化有关 */
        @Nullable
        private LocaleResolver localeResolver;
    
        /** 主题解析器;支持主题效果更换 */
        @Nullable
        private ThemeResolver themeResolver;
    
        /** Handler的映射信息:HandlerMapping */
        @Nullable
        private List<HandlerMapping> handlerMappings;
    
        /** Handler适配器 */
        @Nullable
        private List<HandlerAdapter> handlerAdapters;
    
        /** SpringMVC强大的异常解析功能:异常解析器 */
        @Nullable
        private List<HandlerExceptionResolver> handlerExceptionResolvers;
    
        /** RequestToViewNameTranslator used by this servlet. */
        @Nullable
        private RequestToViewNameTranslator viewNameTranslator;
    
        /** SpringMVC中运行重定向携带数据的功能 */
        @Nullable
        private FlashMapManager flashMapManager;
    
        /** 视图解析器 */
        @Nullable
        private List<ViewResolver> viewResolvers;

       九大组件初始化:DispatcherServlet.java中的

    protected void initStrategies(ApplicationContext context) {
            initMultipartResolver(context);
            initLocaleResolver(context);
            initThemeResolver(context);
            initHandlerMappings(context);
            initHandlerAdapters(context);
            initHandlerExceptionResolvers(context);
            initRequestToViewNameTranslator(context);
            initViewResolvers(context);
            initFlashMapManager(context);
        }

     总结:

      1、所有请求,前端控制器(DispatchServlet)收到请求,调用doDispatch进行处理

      2、根据HandlerMapping中保存的请求映射信息找到,处理当前请求的,处理器执行链(包含拦截器)

      3、根据当前处理器找到它的HandlerAdapter(适配器)

      4、拦截器的preHandle先执行

      5、适配器执行目标方法,并返回ModelAndView

        1)、ModleAttribute注解标注的方法提前运行

        2)、执行目标方法的时候(确定目标方法用的参数)

          a、有注解

          b、无注解

            a)、看是否是Model、Map或其他的

            b)、如果是自定义类型

              1、看隐含模型中有没有,如果有就从隐含模型中拿

              2、如果没有,再看是否SessionAttributes标注的属性,如果是从从session中拿。如果拿不到,抛异常

              3、都不是,就利用反射创建对象

      6、拦截器postHandle执行

      7、处理结果(页面渲染流程)

        1)、如果有异常使用异常解析器处理异常;处理完后返回ModelAndView

        2)、调用render进行渲染

            a、视图解析器根据视图名得到视图对象

            b、视图对象调用render方法

      8、执行拦截器的afterCompletion

      

      

  • 相关阅读:
    线程池源码解析
    String与常量池
    spring循环依赖
    ConcurrentHashMap源码解析(JDK8)
    原子类源码分析
    web service和ejb的区别
    RPC
    hashcode()和equals()的区别
    关于json
    Lifecycle of jsf
  • 原文地址:https://www.cnblogs.com/lxy-java/p/12884455.html
Copyright © 2011-2022 走看看