zoukankan      html  css  js  c++  java
  • DispatcherServlet 流程

    前言

    在 Spring mvc 中,DispatcherServlet主要起着控制客户端请求分发到具体处理程序的作用,并支持对请求进行拦截、参数处理、本地化、文件上传等功能。现查看它的分发的具体流程。

    1. DispatcherServlet 映射配置

    在spring 启动时,如果有 mvc 模块,会将 DispatcherServlet 加载到 web 容器中,进行映射用于处理客户端请求。

    @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
    @ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
    public DispatcherServletRegistrationBean dispatcherServletRegistration(
        DispatcherServlet dispatcherServlet,
        WebMvcProperties webMvcProperties, 
        ObjectProvider<MultipartConfigElement> multipartConfig) 
    {
        	
            DispatcherServletRegistrationBean registration = 
               new DispatcherServletRegistrationBean(dispatcherServlet,
                                                      // 项目请求路径,也就是 dispatcherServlet 映射在web服务器中的路径
                                                      webMvcProperties.getServlet().getPath());
            registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
            registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
            multipartConfig.ifAvailable(registration::setMultipartConfig);
            return registration;
    }
    

    2. DispatcherServlet 结构

    ​ 通过下图,可以看到 DispatcherServlet 继承自 FrameworkServletFrameworkServlet 实现了 HttpServletBean,而 HttpServletBean 实现了 Servlet 接口,这使 DispatcherServlet 能够在注册进容器实例化后就进行初始化,或者在第一次请求调用时进行初始化。

    HttpServletBean 实现了 Servlet#init() 方法,对servlet必要的参数进行配置,然后提供了一个供子类扩展的方法 HttpServletBean#initServletBean()

    @Override
    public final void init() throws ServletException {
       // Set bean properties from init parameters.
       PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
       if (!pvs.isEmpty()) {
          try {
             BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
             ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
             bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
             initBeanWrapper(bw);
             bw.setPropertyValues(pvs, true);
          }
          catch (BeansException ex) {
             if (logger.isErrorEnabled()) {
                logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
             }
             throw ex;
          }
       }
       // 为子类提供的初始化接口
       // Let subclasses do whatever initialization they like.
       initServletBean();
    }
    

    FrameworkServlet 实现了 HttpServletBean#initServletBean() 方法,提供了 WebApplicationContext 属性和initFrameworkServlet 方法,支持子类的自定义初始化操作, FrameworkServlet#initWebApplicationContext() 中调用了 FrameworkServlet#onRefresh() 方法,DispatcherServlet 通过实现 FrameworkServlet#onRefresh() 方法来进行初始化。

    @Override
    protected final void initServletBean() throws ServletException {
       // .... 略
       try {
          this.webApplicationContext = initWebApplicationContext();
          initFrameworkServlet();
       }
       catch (ServletException | RuntimeException ex) {
          logger.error("Context initialization failed", ex);
          throw ex;
       }
       // .... 略
    }
    
    protected WebApplicationContext initWebApplicationContext() {
        // 获取 spring ioc 容器
        WebApplicationContext rootContext =
            WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;
    
        if (this.webApplicationContext != null) {
            // webApplicationContext 将在servlet创建时就传递进来
            wac = this.webApplicationContext;
            // 检查类型
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
                // 上下文未处于活动状态时进入
                if (!cwac.isActive()) {
                    // 设置上级
                    if (cwac.getParent() == null) {
                        cwac.setParent(rootContext);
                    }
                    // 配置并添加监听器,并重新刷新 ApplicationContext
                    configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
        if (wac == null) {
            // 查找 WebApplicationContext,肯定存在,不存在会抛出异常,一般也不会进入该方法
            wac = findWebApplicationContext();
        }
        
        if (wac == null) {
            // 创建 WebApplicationContext
            wac = createWebApplicationContext(rootContext);
        }
     	// 未触发刷新事件时,触发 onRefresh 事件
        if (!this.refreshEventReceived) {
            // 调用 onRefresh
            synchronized (this.onRefreshMonitor) {
                onRefresh(wac);
            }
        }
        // 将上下文与servlet对应
        if (this.publishContext) {
            // Publish the context as a servlet context attribute.
            String attrName = getServletContextAttributeName();
            getServletContext().setAttribute(attrName, wac);
        }
        return wac;
    }
    
    protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
        // ... 略
        // 设置监听器 ContextRefreshListener,监听ContextRefreshedEvent事件
        wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));
    	
        // ... 略
        // 刷新
        wac.refresh();
    }
    
    // 刷新操作
    protected void onRefresh(ApplicationContext context) {
        // For subclasses: do nothing by default.
    }
    
    // 响应 ContextRefreshedEvent 事件
    public void onApplicationEvent(ContextRefreshedEvent event) {
        this.refreshEventReceived = true;
        synchronized (this.onRefreshMonitor) {
            onRefresh(event.getApplicationContext());
        }
    }
    
    // ContextRefresh监听器
    private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {
    
        @Override
        public void onApplicationEvent(ContextRefreshedEvent event) {
            FrameworkServlet.this.onApplicationEvent(event);
        }
    }
    

    3. DispatcherServlet 初始化

    ​ 在加载 DispatcherServlet 类时会进入静态块加载 DispatcherServlet.properties 配置文件,这个配置文件中配置了 DispatcherServlet 默认加载的属性类,如下

    static {
        // 从配置文件中加载默认实现,spring内部实现,不打算让开发程序人员自定义实现
        try {
        ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
        defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
        }
        catch (IOException ex) {
        throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
        }
    }
    
    # Default implementation classes for DispatcherServlet's strategy interfaces.
    # Used as fallback when no matching beans are found in the DispatcherServlet context.
    # Not meant to be customized by application developers.
    
    org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
    
    org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
    
    org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,
    	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,
    	org.springframework.web.servlet.function.support.RouterFunctionMapping
    
    org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,
    	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,
    	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,
    	org.springframework.web.servlet.function.support.HandlerFunctionAdapter
    
    
    org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,
    	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,
    	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
    
    org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
    
    org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
    
    org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
    

    由于 FrameworkServletinitServletBean() 方法提供了 FrameworkServlet#onRefresh() 方法来触发刷新, DispatcherServlet 实现 FrameworkServlet#onRefresh() 方法来在刷新时完成初始化操作。

    protected void onRefresh(ApplicationContext context) {
       initStrategies(context);
    }
    
    protected void initStrategies(ApplicationContext context) {
        // 下面初始化的bean都有默认的类,如果没有自定义,则使用默认的,在 DispatcherServlet.properties 中定义
        // 初始化上传文件处理器
        initMultipartResolver(context);
        // 初始化i18n国际化资源处理器
        initLocaleResolver(context);
        // 初始化themeResolver
        initThemeResolver(context);
        // 初始化请求映射器
        initHandlerMappings(context);
        // 初始化请求处理适配器
        initHandlerAdapters(context);
        // 初始化异常处理器
        initHandlerExceptionResolvers(context);
        // 初始化请求视图转换器
        initRequestToViewNameTranslator(context);
        // 初始化视图解析器
        initViewResolvers(context);
        // 初始化请求参数在请求之间传递
        initFlashMapManager(context);
    }
    

    4. DispatcherServlet 处理请求流程

    FrameworkServlet 重写了 HttpServlet#service(),在实现中添加了 Http Patch 类型请求的支持,将处理委托给 FrameworkServlet#processRequest()FrameworkServlet#processRequest()控制了请求的处理流程,提供了FrameworkServlet#doService(),让子类实现来自定义处理请求。

    ​ 在将 DispatcherServlet 注册进 WebServer 中时,将会映射项目的访问路径,当有请求与该路径匹配,并且实现了 FrameworkServlet,进入 DispatcherServlet#doService() 中响应请求。

    FrameworkServlet#service() 方法代码

    /**
     * FrameworkServlet 实现了支持 PATCH 请求,Servlet 是不支持 PATCH 请求的 
     * doGetdoPostdoDeletedoPut 方法的实现都是直接调用 processRequest(),
     * 而 doOptionsdoTrace 需要进行专门的处理后在调用processRequest()
     */
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
          throws ServletException, IOException {
    
       HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
       if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
          processRequest(request, response);
       }
       else {
          super.service(request, response);
       }
    }
    

    FrameworkServlet#processRequest() 中,在请求上绑定 AttributesLocaleContext 、添加并发处理控制器。

    FrameworkServlet#processRequest() 方法代码

    /**
     * spring mvc 处理请求的入口
     */
    protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
          throws ServletException, IOException {
    
       long startTime = System.currentTimeMillis();
       // 异常
       Throwable failureCause = null;
    
       // 获取之前的语言环境,可能在RequestContextFilter 中已经设置
       LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
        
       // 本次请求的语言环境
       LocaleContext localeContext = buildLocaleContext(request);
       // 获取之前的attribute,可能在RequestContextFilter 中已经设置
       RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
        
       // 构建请求的attribute
       // 如果 previousAttributes 不为空或 previousAttributes 是 ServletRequestAttributes 的实例,则创建一个新的,否则返回null
       ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
        
       // 获取 WebAsyncManager,用于管理异步请求的处理
       // 他是绑定在这个请求的 RequestAttributes 中的,如果没有对应的将会绑定一个新的 WebAsyncManager
       WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        
       // 注册回调Interceptor
       // 固定增加了 RequestBindingInterceptor 拦截器,用于绑定 LocaleContext 和 RequestAttributes,他的绑定逻辑与下面的
       // initContextHolders 逻辑一样,在RequestBindingInterceptor#preProcess 中调用,
       // 并且在 RequestBindingInterceptor#postProcess 中将LocaleContext 和 RequestAttributes清空
       asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
        
       // 将 localeContext 和 requestAttributes 绑定在当前线程上
       initContextHolders(request, localeContext, requestAttributes);
    
       // 处理请求
       try {
          // 这个方法中将会处理所有的spring请求逻辑,有子类实现
          doService(request, response);
       }
       catch (ServletException | IOException ex) {
          // 记录异常信息
          failureCause = ex;
          throw ex;
       }
       catch (Throwable ex) {
          // 记录异常信息
          failureCause = ex;
          throw new NestedServletException("Request processing failed", ex);
       }
       finally {
          // 清空当前线程绑定的 localContext 和 Attribute,与 RequestBindingInterceptor#postProcess 中的逻辑一样
          resetContextHolders(request, previousLocaleContext, previousAttributes);
          if (requestAttributes != null) {
             // 请求执行结束,注销回调
             requestAttributes.requestCompleted();
          }
          //debug: 打印日志,如果有异常信息打印异常
          logResult(request, response, failureCause, asyncManager);
           
          // 向spring Context 发布请求处理完成事件 ServletRequestHandledEvent
          publishRequestHandledEvent(request, response, startTime, failureCause);
       }
    }
    

    FrameworkServlet 重写了 HttpServlet#service(),并将处理请求交给子类实现,提供了doService方法。

    doService 方法中,对请求做准备、清理工作,将请求的处理工作交给了 doDispatcher()

    doDispatcher 方法里面,主要逻辑有:

    1. 根据请求路径匹配业务执行器 MapperHandler,并与HandlerInterceptor组成执行器链后交给处理适配器HandlerAdapter

    2. 调用过虑器链 mapperHandler#getInterceptors()

    3. 执行 HandlerAdapter#handler() 执行具体业务逻辑,返回结果

    4. 根据返回结果进行视图解析或直接返回数据结果。

    5. 执行完具体业务逻辑后,执行 HandlerInterceptor#afterCompletion() ,最后执行清理工作 HandlerInterceptor#afterCompletion()

    6. 响应数据,请求完成。

    查看 DispatcherServlet 实现 FrameworkServlet#doService() 的代码。

    /**
     * 在该方法中,会将实际的请求处理委托给 doDispatch 方法,这个方法会绑定属性以供处理请求时使用。
     */
    @Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
       // 打印请求内容, debug 下才会打印
       logRequest(request);
    
       // Keep a snapshot of the request attributes in case of an include,
       // to be able to restore the original attributes after the include.
       // 临时存储该请求的 attribute 的快照,供处理完请求后将 attribute 还原。
       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.
       // 绑定属性到 attribute 
       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());
    
        	
       // 缓存 attribute
       if (this.flashMapManager != null) {
          // 删除过期缓存
          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);
             }
          }
       }
    }
    
    /**
     * 执行doDispatcher,该方法执行了所有请求的基本逻辑
     */
    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 {
                // 检查是否上传文件,如果是将转换为 MultipartHttpServletRequest 请求
                processedRequest = checkMultipart(request);
                // 是上传文件操作?
                multipartRequestParsed = (processedRequest != request);
    
                // Determine handler for the current request.
                //1. 获取 handler
                // 获取当前的请求对应的处理器,使用 @Conatroller 或 @RequestMapper 注解的处理程序。
                // 返回的是一个 HandlerExecutionChain 拦截器链,由处理程序对象(方法)和 拦截器组成
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }
    
                // Determine handler adapter for the current request.
                //2. 获取handlerAdapter
                // 获取handlerAdapter 对应的处理器适配器,通过 HandlerAdapter#supports 来进行判断应该使用哪个 HandlerAdapter
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
                // Process last-modified header, if supported by the handler.
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                // 如果是get或head方法,判断他是否改变过。
                if (isGet || "HEAD".equals(method)) {
                    // 使用对应的 handler 来判断资源是否修改过
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
    			
                // 执行 interceptor#preHandle 方法
                // 如果 interceptor#preHandle 返回false,将会调用匹配拦截器的 interceptor#afterCompletion 方法
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
    			
                //3. 执行业务逻辑
                //4. 内部已经处理了部分 响应逻辑
                // Actually invoke the handler.
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
                // 是否是并发处理,如果是并发处理直接返回
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
    			
                // 对视图名称进行处理
                applyDefaultViewName(processedRequest, mv);
                // 执行匹配拦截器 interceptor.postHandle 方法
                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);
            }
            // 解析视图,如果发生了异常,则会解析异常视图,
            // 解析视图完成后,是在并发处理请求中,则直接返回,
            // 不在并发执行流程中,将会并执行匹配所有拦截器的  interceptor#afterCompletion 方法
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            // 执行匹配所有拦截器的  interceptor#afterCompletion 方法
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
            // 执行匹配拦截器的  interceptor#afterCompletion 方法
            triggerAfterCompletion(processedRequest, response, mappedHandler,
                                   new NestedServletException("Handler processing failed", err));
        }
        finally {
            // 如果是在并发执行,则在这里调用 interceptor#afterCompletion 方法
            if (asyncManager.isConcurrentHandlingStarted()) {
                // Instead of postHandle and afterCompletion
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                // 是上传请求,则将清除 Multipart
                // Clean up any resources used by a multipart request.
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }
    
    1. 获取handler

    ​ 在spring mvc项目启动时,会将 HandlerMapping注册进 spring 容器中,HandlerMapping 接口提供了获取执行业务方法的能力。

    public interface HandlerMapping {
    	@Nullable
    	HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
    }
    

    ​ 使用 RequestMappingHandlerMapping 进行举例,他是 AbstractHandlerMethodMapping 的实现类,AbstractHandlerMethodMapping 实现了 InitializingBean ,可以在项目启动后进行初始化,对 controllerRequestMapping 进行解析,结果保存进AbstractHandlerMethodMapping#mappingRegistry 中。

    ​ 在请求到达时,则是通过请求的路径来获取 HandlerMethod ,与拦截器组成拦截器链对象 HandlerExecutionChain

    public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
          implements HandlerMapping, Ordered, BeanNameAware {
          	
        public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
            // 根据请求获取 handler 对象
    		Object handler = getHandlerInternal(request);
    		if (handler == null) {
    			handler = getDefaultHandler();
    		}
            // 不存在返回空
    		if (handler == null) {
    			return null;
    		}
    		// Bean name or resolved handler?
    		if (handler instanceof String) {
    			String handlerName = (String) handler;
    			handler = obtainApplicationContext().getBean(handlerName);
    		}
    		
            // 获取执行器链对象,并将拦截器装入其中
    		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
    
    		if (logger.isTraceEnabled()) {
    			logger.trace("Mapped to " + handler);
    		}
    		else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
    			logger.debug("Mapped to " + executionChain.getHandler());
    		}
    			
            // 跨域处理
    		if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
    			CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
    			CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
    			config = (config != null ? config.combine(handlerConfig) : handlerConfig);
    			executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    		}
    
    		return executionChain;
    	}
        
        /**
         * 获取 HandlerExecutionChain
         */
        protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    		HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
    				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
    
    		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request, LOOKUP_PATH);
            // 将拦截器加入到执行器链
    		for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
    			if (interceptor instanceof MappedInterceptor) {
    				MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
    				if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
    					chain.addInterceptor(mappedInterceptor.getInterceptor());
    				}
    			}
    			else {
    				chain.addInterceptor(interceptor);
    			}
    		}
    		return chain;
    	}
    }
    
    2. 获取HandlerAdapter

    ​ 使用 HandlerAdapter#supports() 判断是否匹配,如果匹配,返回对应的 HandlerAdapter

    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
       if (this.handlerAdapters != null) {
          for (HandlerAdapter adapter : this.handlerAdapters) {
             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. 执行业务逻辑

    ​ 执行具体业务逻辑主要是通过 HandlerAdapter 来执行, AbstractHandlerMethodAdapter 抽象类实现了HandlerAdapter , 并提供了一个供子类实现的抽象方法 AbstractHandlerMethodAdapter#handleInternal()

    RequestMappingHandlerAdapter 通过实现了 AbstractHandlerMethodAdapter#handleInternal() 来执行具体的业务逻辑。

    @Override
    protected ModelAndView handleInternal(HttpServletRequest request,
          HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
       ModelAndView mav;
       // 检查是否支持该请求,比如是否支持该请求的类型
       checkRequest(request);
    
       // Execute invokeHandlerMethod in synchronized block if required.
       // 是否同步响应同一客户端的请求,以session为单位
       if (this.synchronizeOnSession) {
          // 获取session
          HttpSession session = request.getSession(false);
          if (session != null) {
             // 根据session获取同步互斥变量,通过在 request#attribute 中保存 session 对象来实现
             Object mutex = WebUtils.getSessionMutex(session);
             synchronized (mutex) {
                // 同步执行业务逻辑
                mav = invokeHandlerMethod(request, response, handlerMethod);
             }
          }
          else {
             // 没有session不同步执行业务逻辑
             // No HttpSession available -> no mutex necessary
             mav = invokeHandlerMethod(request, response, handlerMethod);
          }
       }
       else {
          // 不进行同步执行业务逻辑
          // No synchronization on session demanded at all...
          mav = invokeHandlerMethod(request, response, handlerMethod);
       }
       // 对响应进行缓存
       if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
          if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
             applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
          }
          else {
             prepareResponse(response);
          }
       }
    
       return mav;
    }
    
    /**
     * 执行业务逻辑
     */
    @Nullable
    protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
                                               HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    	//1. 对本次请求和响应进行封装,他是一个适配器,管理了request、response、request attribute。
        ServletWebRequest webRequest = new ServletWebRequest(request, response);
        try {
            //2.专门处理使用 @InitBinder 注解的方法的工厂,binderFactory 中包含了 Validator、FormattingConversionService
            WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
            
            //3. 处理使用 @ModelAttribute 注解的方法
            ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
    
    		//4. 创建业务方法调用器,由他来通过反射调用业务方法
            ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
            // 设置参数解析器
            if (this.argumentResolvers != null) {
                invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
            }
            // 设置返回值处理器
            if (this.returnValueHandlers != null) {
                invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
            }
            // 设置 @InitBinder 处理工厂
            invocableMethod.setDataBinderFactory(binderFactory);
            // 设置参数名称解析器
            invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
    
            // 创建modelAndView容器
            ModelAndViewContainer mavContainer = new ModelAndViewContainer();
            // 设置其他请求转发到该请求的 Attributes 属性值
            mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
            
            // 初始化model:执行使用了 @InitBinder 注解的方法,并将绑定结果与 @ModelAttribute 注解标记的属性进行匹配
            modelFactory.initModel(webRequest, mavContainer, invocableMethod);
            
            mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
    
            // 创建异步请求
            AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
            // 设置超时时间
            asyncWebRequest.setTimeout(this.asyncRequestTimeout);
    
            // 获取异步请求管理器
            WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
            // 设置
            asyncManager.setTaskExecutor(this.taskExecutor);
            asyncManager.setAsyncWebRequest(asyncWebRequest);
            asyncManager.registerCallableInterceptors(this.callableInterceptors);
            asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
    
            // 并发相关处理?
            if (asyncManager.hasConcurrentResult()) {
                Object result = asyncManager.getConcurrentResult();
                mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
                asyncManager.clearConcurrentResult();
                LogFormatUtils.traceDebug(logger, traceOn -> {
                    String formatted = LogFormatUtils.formatValue(result, !traceOn);
                    return "Resume with async result [" + formatted + "]";
                });
                invocableMethod = invocableMethod.wrapConcurrentResult(result);
            }
    
            //5. 调用请求对应的方法
            invocableMethod.invokeAndHandle(webRequest, mavContainer);
            if (asyncManager.isConcurrentHandlingStarted()) {
                return null;
            }
    		
            // 处理视图,这里是对返回的视图名称或 ModelAndView 进行组装
            return getModelAndView(mavContainer, modelFactory, webRequest);
        }
        finally {
            webRequest.requestCompleted();
        }
    }
    
    /**
     * 2. 生成处理 使用 @InitBinder 注解的方法的工厂
     * @InitBinder 是标记在请求到达方法前对参数进行额外处理,比如修改参数、忽略参数等操作 (WebDataBinder)
     */
    private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
        // 2.1 查找使用了@RequestMapper 的类和使用了 @InitBinder 注解的方法,并缓存进对象中
        // 作用域只针对该handlerType
        Class<?> handlerType = handlerMethod.getBeanType();
        Set<Method> methods = this.initBinderCache.get(handlerType);
        if (methods == null) {
            methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
            this.initBinderCache.put(handlerType, methods);
        }
        // 保存使用了 @InitBinder 注解的方法
        List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>();
        
        //2.2 项目中使用 @ControllerAdvice 注解标记类,并且这个类中有使用 @InitBinder 注解的方法
        // 作用域针对全局
        this.initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
            // 检查请求处理类 controller 是否满足 @ControllerAdvice 注解的要求
            if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
                // 找到 @ControllerAdvice 注解使用类的实例
                Object bean = controllerAdviceBean.resolveBean();
                // 保存使用了 @InitBinder 注解的方法
                for (Method method : methodSet) {
                    initBinderMethods.add(createInitBinderMethod(bean, method));
                }
            }
        });
        //2.3 保存使用了 @InitBinder 注解的方法
        for (Method method : methods) {
            Object bean = handlerMethod.getBean();
            initBinderMethods.add(createInitBinderMethod(bean, method));
        }
        //2.4 创建数据绑定工程:用于生成 解析用了 @InitBinder 注解的方法的工厂类。
        return createDataBinderFactory(initBinderMethods);
    }
    
    /**
     * 3. 生成处理使用 @ModelAttribute 注解的 ModelFactory
     */
    private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
        
        // 3.1 查找在该类中未使用 @RequestMapper 注解但是使用了 @ModelAttribute 注解的方法
        SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
        Class<?> handlerType = handlerMethod.getBeanType();
        Set<Method> methods = this.modelAttributeCache.get(handlerType);
        if (methods == null) {
            methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
            this.modelAttributeCache.put(handlerType, methods);
        }
        List<InvocableHandlerMethod> attrMethods = new ArrayList<>();
        
        // Global methods first
        //3.2 项目中使用 @ControllerAdvice 注解类中的所有方法
        // 作用域针对全局
        this.modelAttributeAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
            // 查找使用了 @ControllerAdvice 注解的类中的方法,并为每个方法创建 InvocableHandlerMethod 对象
            if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
                Object bean = controllerAdviceBean.resolveBean();
                for (Method method : methodSet) {
                    attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
                }
            }
        });
        
        //3.3 创建 InvocableHandlerMethod 对象
        for (Method method : methods) {
            Object bean = handlerMethod.getBean();
            attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
        }
        //3.4 创建 ModelFactory,其中保存了每个方法和这个方法使用了 @ModelAttribute 注解的属性。
        return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
    }
    

    invokeHandlerMethod 通过执行 ServletInvocableHandlerMethod#invokeAndHandle() 来调用业务方法。

    /**
     * 使用反射调用业务方法
     */
    public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
          Object... providedArgs) throws Exception {
    
       // 1. 调用业务方法
       Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        
       // 设置响应状态
       setResponseStatus(webRequest);
      
       if (returnValue == null) {
          // 返回值为空,检查资源是否改变过、响应状态不为空、请求已经处理完成
          if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
             // 请求内容为改变
             disableContentCachingIfNecessary(webRequest);
             // 请求已在业务处理程序中完成
             mavContainer.setRequestHandled(true);
             return;
          }
       }
       // 请求已在业务处理程序中完成
       else if (StringUtils.hasText(getResponseStatusReason())) {
          mavContainer.setRequestHandled(true);
          return;
       }
    	
       // 请求未完成
       mavContainer.setRequestHandled(false);
       // 在 invokeHandlerMethod 方法中将默认的返回值处理器设置进 ServletInvocableHandlerMethod 中了
       Assert.state(this.returnValueHandlers != null, "No return value handlers");
       try { 
          // 根据返回值或使用的注解,找到对应的返回值处理器,然后将请求结果刷新到响应中,
          // 或者将返回值设置进 mavContainer 中,方便后面解析
          this.returnValueHandlers.handleReturnValue(
                returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
       }
       catch (Exception ex) {
          if (logger.isTraceEnabled()) {
             logger.trace(formatErrorForReturnValue(returnValue), ex);
          }
          throw ex;
       }
    }
    
    /**
     * 1 调用业务方法
     */
    @Nullable
    public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
                                   Object... providedArgs) throws Exception {
    	//1.1  解析方法的入参,使用对应的参数解析器对请求进行解析,得到参数 : HandlerMethodArgumentResolver
        Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
        if (logger.isTraceEnabled()) {
            logger.trace("Arguments: " + Arrays.toString(args));
        }
        //1.2 调用方法
        return doInvoke(args);
    }
    
    /**
     * 1.2 调用业务方法
     */
    @Nullable
    protected Object doInvoke(Object... args) throws Exception {
        ReflectionUtils.makeAccessible(getBridgedMethod());
        // 使用反射调用业务方法
        return getBridgedMethod().invoke(getBean(), args);
    }
    
    4. 返回请求结果
        业务执行后,返回结果会根据返回值类型和使用的注解等信息来匹配对应的 `HandlerMethodReturnValueHandler` ,取到对应的返回值处理器后,就会调用 `HandlerMethodReturnValueHandler#handleReturnValue()`对进行处理。
    

    ​ 如 HttpEntityMethodProcessor 处理使用 HttpEntity 做为返回值的方法,也可以解析请求方法入参类型使用 RequestEntity HttpEntity 的方法参数进行解析 。

    RequestResponseBodyMethodProcessor 则对使用 @RequestBody 注解的方法进行参数解析,和使用@ResponseBody注解的方法进行返回值处理,而 @RestController 注解定义时使用了 @ResponseBody 注解,所以 @RestController@ResponseBody 的功能一样。

    ModelAndViewMethodReturnValueHandler 则解析返回值类型为 ModelAndView 的结果,与其他类型的返回值处理程序不同的是,该类不会直接返回结果,而是根据结果解析出对应的视图对象 ModelAndView,交给 DispatcherServlet中的 ViewResolver 来渲染视图,响应给客户端。

  • 相关阅读:
    Python之位移操作符所带来的困惑
    SR采用PubSubHubbub协议实时接收GReaderSharedItems更新
    如何找到正在热传的微博客图片?
    手持设备:懒人的互联网音乐智能同步/播放器
    七十二般变化解得了三灾?
    如何测量Google Reader用户的分享活跃度
    基于Google Reader发展起来的个性化推荐系统之三大问题
    Python检测Windows剩余磁盘空间
    Python 内部类,内部类调用外部类属性,方法
    禁止IE页面自动跳转到EDGE浏览器的方法
  • 原文地址:https://www.cnblogs.com/diandiandidi/p/14486477.html
Copyright © 2011-2022 走看看