<返回更多

SpringBoot中的Controller详解

2021-11-04    程序yuan
加入收藏

SpringBoot中的Controller注册

本篇将会以Servlet为切入点,通过源码来看web容器中的Controller是如何注册到HandlerMApping中。请求来了之后,web容器是如何根据请求路径找到对应的Controller方法并执行的。

先讲下本文的大概思路和流程图:

  1. 我们经常使用的RequestMapping这个注解对应的方法最终会被RequestMappingHandlerMapping处理,并封装成一个HandlerMethod注入到自己内部的mappingRegistry 容器中。这一步是Controller的注册,被执行的触发点是因为RequestMappingHandlerMapping这个类实现了InitializingBean接口,由Spring容器触发。
  2. Tomcat容器被启动的时候,最后会调用Servlet的init方法,这里会把所有的HandlerMapping注册到自己内部的handlerMappings属性中。这样Servlet和RequestMapping注解的Controller就建立起了间接关系。
  3. 当请求到来的时候,tomcat拿到并封装好请求体后会调用Servlet的service方法。这个方法最终会走到 DispatcherServlet的doDispatch方法,这个方法中会找到最适合的HandlerMapping并取出对应的HadlerMethod,然后给对应的HandlerAdapter执行.
  4. controller注册流程图
SpringBoot中的Controller详解

 

5. controller发现和使用流程图

SpringBoot中的Controller详解

 

正文开始

处理请求的DispatcherServlet

SpringBoot中的Controller详解

 

Servlet接口的源码

public interface Servlet {
    //初始化
    public void init(ServletConfig config) throws ServletException;

    //响应请求
    public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;

    //获取servlet信息
    public String getServletInfo();
        
    //服务停止时回调
    public void destroy();
}
复制代码

springboot内置了tomcat容器,而tomcat容器是遵循了servlet规范的。servlet规范中定义了初始化、响应、获取配置信息和销毁时回调钩子。从servlet的规范中可以看出,tomcat启动时会调用servlet的init方法,处理请求时会调用service方法,容器销毁时会调用destroy方法。servlet中最核心的实现就是我们所熟知的DispatchServlet,看下DispatchServlet的继承体系

SpringBoot中的Controller详解

 

从DispatchServlet的继承体系中,看下Servlet的初始化做了什么。

Servlet的初始化 init

HttpServletBean中的init方法源码

@Override
public final void init() throws ServletException {

   // 设置servlet的属性
   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;
      }
   }

   // 具体的初始化方法交给子类实现
   initServletBean();
}
//空实现,具体的由子类实现
protected void initServletBean() throws ServletException {
}
复制代码

从HttpServletBean中的init方法可以看到,这里核心的就是设置了Servlet的一些 bean properties,继续到子类 FrameworkServlet中看initServletBean方法

@Override
protected final void initServletBean() throws ServletException {
   getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
   if (logger.isInfoEnabled()) {
      logger.info("Initializing Servlet '" + getServletName() + "'");
   }
   long startTime = System.currentTimeMillis();

   try {
      //这里初始化了web的上下文,这里会初始化Servlet的九大策略
      this.webApplicationContext = initWebApplicationContext();
      //这个方法也是空实现
      initFrameworkServlet();
   }
   catch (ServletException | RuntimeException ex) {
      logger.error("Context initialization failed", ex);
      throw ex;
   }

   if (logger.isDebugEnabled()) {
      String value = this.enableLoggingRequestDetails ?
            "shown which may lead to unsafe logging of potentially sensitive data" :
            "masked to prevent unsafe logging of potentially sensitive data";
      logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +
            "': request parameters and headers will be " + value);
   }

   if (logger.isInfoEnabled()) {
      logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
   }
}

//初始化上下文
protected WebApplicationContext initWebApplicationContext() {
   WebApplicationContext rootContext =
         WebApplicationContextUtils.getWebApplicationContext(getServletContext());
   WebApplicationContext wac = null;

   if (this.webApplicationContext != null) {
      wac = this.webApplicationContext;
      if (wac instanceof ConfigurableWebApplicationContext) {
         ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
         if (!cwac.isActive()) {
            if (cwac.getParent() == null) {
               cwac.setParent(rootContext);
            }
            configureAndRefreshWebApplicationContext(cwac);
         }
      }
   }
   if (wac == null) {
      wac = findWebApplicationContext();
   }
   if (wac == null) {
      wac = createWebApplicationContext(rootContext);
   }

   if (!this.refreshEventReceived) {
      synchronized (this.onRefreshMonitor) {
          //springboot只会进入这个方法,这个方法是空实现,具体实现在子类DispatchServlet
         onRefresh(wac);
      }
   }

   if (this.publishContext) {
      String attrName = getServletContextAttributeName();
      getServletContext().setAttribute(attrName, wac);
   }

   return wac;
}
复制代码

接着跟进DispatchServlet的onRefresh方法,这个方法中会初始化DispatchServlet的九大策略,这里我们只关心initHandlerMappings方法

@Override
protected void onRefresh(ApplicationContext context) {
   initStrategies(context);
}

//初始化策略
protected void initStrategies(ApplicationContext context) {
   initMultipartResolver(context);
   initLocaleResolver(context);
   initThemeResolver(context);
   //这个是我们关注的核心,Controller注册就在这里实现
   initHandlerMappings(context);
   //这个是处理Controller方法调用的,逻辑跟上面的initHandlerMappings差不多
   initHandlerAdapters(context);
   initHandlerExceptionResolvers(context);
   initRequestToViewNameTranslator(context);
   initViewResolvers(context);
   initFlashMapManager(context);
}
复制代码

核心看下initHandlerMappings方法

private void initHandlerMappings(ApplicationContext context) {
   this.handlerMappings = null;
    //默认为true
   if (this.detectAllHandlerMappings) {
      //默认的HandlerMapping有8个,这里我们只关心RequestMappingHandlerMapping这个类
      Map<String, HandlerMapping> matchingBeans =
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
      if (!matchingBeans.isEmpty()) {
         this.handlerMappings = new ArrayList<>(matchingBeans.values());
         //排序
         AnnotationAwareOrderComparator.sort(this.handlerMappings);
      }
   }
   else {
      try {
         HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
         //这里就让Serlvet和Controller建立起了间接关系了,这个方法主要是为了给handlerMappings属性赋值
         this.handlerMappings = Collections.singletonList(hm);
      }
      catch (NoSuchBeanDefinitionException ex) {
      }
   }

   //这里如果没有HanlderMapping的话,会给一个默认的处理
   if (this.handlerMappings == null) {
      this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
      if (logger.isTraceEnabled()) {
         logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
               "': using default strategies from DispatcherServlet.properties");
      }
   }
}
复制代码

看下默认的 HandlerMapping 有哪些

SpringBoot中的Controller详解

 

这里我们只关心
RequestMappingHandlerMapping这个类,这个类就是处理我们Controller上的RequestMapping注解的类。

注意这里的handlerMappings,后面处理请求的时候,会从handlerMappings中选择一个最合适的HandlerMapping来处理请求

Servlet的请求处理 service

HttpServlet中的service方法源码

/**
* 这个方法只是将ServletRequest强转为HttpServletRequest
* ServletResponse强转为HttpServletResponse
*/
@Override
public void service(ServletRequest req, ServletResponse res)
    throws ServletException, IOException {

    HttpServletRequest  request;
    HttpServletResponse response;

    try {
        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;
    } catch (ClassCastException e) {
        throw new ServletException(lStrings.getString("http.non_http"));
    }
    //接着看这个
    service(request, response);
}

protected void service(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException {
    //获取方法类型
    String method = req.getMethod();
    //根据不同的方法类型调用不同的方法,从doGet进去,看子类FrameworkServlet的doGet方法
    if (method.equals(METHOD_GET)) {
        long lastModified = getLastModified(req);
        if (lastModified == -1) {
            doGet(req, resp);
        } else {
            long ifModifiedSince;
            try {
                ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
            } catch (IllegalArgumentException iae) {
                ifModifiedSince = -1;
            }
            if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                maybeSetLastModified(resp, lastModified);
                doGet(req, resp);
            } else {
                resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            }
        }

    } else if (method.equals(METHOD_HEAD)) {
        long lastModified = getLastModified(req);
        maybeSetLastModified(resp, lastModified);
        doHead(req, resp);

    } else if (method.equals(METHOD_POST)) {
        doPost(req, resp);

    } else if (method.equals(METHOD_PUT)) {
        doPut(req, resp);

    } else if (method.equals(METHOD_DELETE)) {
        doDelete(req, resp);

    } else if (method.equals(METHOD_OPTIONS)) {
        doOptions(req,resp);

    } else if (method.equals(METHOD_TRACE)) {
        doTrace(req,resp);

    } else {
        String errMsg = lStrings.getString("http.method_not_implemented");
        Object[] errArgs = new Object[1];
        errArgs[0] = method;
        errMsg = MessageFormat.format(errMsg, errArgs);

        resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
    }
}

//FrameworkServlet的doGet方法
@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    //继续跟
   processRequest(request, response);
}

rotected final void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

   long startTime = System.currentTimeMillis();
   Throwable failureCause = null;

   LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
   LocaleContext localeContext = buildLocaleContext(request);

   RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
   ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

   WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
   asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

   initContextHolders(request, localeContext, requestAttributes);

   try {
       //这里处理请求,继续跟,看子类DispatchServlet的doService方法
      doService(request, response);
   }
   catch (ServletException | IOException ex) {
      failureCause = ex;
      throw ex;
   }
   catch (Throwable ex) {
      failureCause = ex;
      throw new NestedServletException("Request processing failed", ex);
   }

   finally {
      resetContextHolders(request, previousLocaleContext, previousAttributes);
      if (requestAttributes != null) {
         requestAttributes.requestCompleted();
      }
      logResult(request, response, failureCause, asyncManager);
      publishRequestHandledEvent(request, response, startTime, failureCause);
   }
}
复制代码

DispatchServlet的doService方法

@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 打印日志
   logRequest(request);
   //保存快照
   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));
         }
      }
   }
    //设置属性
   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());

   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(request, response);
   }
   finally {
      if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
         if (attributesSnapshot != null) {
            restoreAttributesAfterInclude(request, attributesSnapshot);
         }
      }
   }
}
复制代码

DispatchServlet的doDispatch方法

SpringBoot中的Controller详解

 

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);

         // 获取当前请求的handler
         mappedHandler = getHandler(processedRequest);
         if (mappedHandler == null) {
             //404
            noHandlerFound(processedRequest, response);
            return;
         }

         // 获取处理当前请求的handlerAdapter
         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
         
         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;
         }

         // 请求对应的方法在这里被执行
         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);
         }
      }
   }
}

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   if (this.handlerMappings != null) {
      for (HandlerMapping mapping : this.handlerMappings) {
      //这里的mapping就是接下来要讲到的RequestMappingHandlerMapping
         HandlerExecutionChain handler = mapping.getHandler(request);
         if (handler != null) {
            return handler;
         }
      }
   }
   return null;
}
复制代码

这里可以记录Servlet处理请求的调用链 service -> doGet -> processRequest -> doService -> doDispatch

RequestMappingHandlerMapping 做了啥

SpringBoot中的Controller详解

 

从上面的继承图可以看出
RequestMappingHandlerMapping实现了InitializingBean接口,所以初始化的时候会调用afterPropertiesSet方法。

@Override
@SuppressWarnings("deprecation")
public void afterPropertiesSet() {
    //配置
   this.config = new RequestMappingInfo.BuilderConfiguration();
   this.config.setUrlPathHelper(getUrlPathHelper());
   this.config.setPathMatcher(getPathMatcher());
   this.config.setSuffixPatternMatch(useSuffixPatternMatch());
   this.config.setTrailingSlashMatch(useTrailingSlashMatch());
   this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
   this.config.setContentNegotiationManager(getContentNegotiationManager());
    //这里是核心,会把所有controller注册进去
   super.afterPropertiesSet();
}
复制代码

接着看父类
AbstractHandlerMethodMapping的afterPropertiesSet方法

@Override
public void afterPropertiesSet() {
   initHandlerMethods();
}

protected void initHandlerMethods() {
   for (String beanName : getCandidateBeanNames()) {
      if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
      //这里会注册controller
         processCandidateBean(beanName);
      }
   }
   handlerMethodsInitialized(getHandlerMethods());
}

protected void processCandidateBean(String beanName) {
   Class<?> beanType = null;
   try {
      beanType = obtainApplicationContext().getType(beanName);
   }
   catch (Throwable ex) {
      if (logger.isTraceEnabled()) {
         logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
      }
   }
   //这里的isHandler会判断是否有Controller或RequestMapping注解
   if (beanType != null && isHandler(beanType)) {
      //这里会注册controller,接着跟
      detectHandlerMethods(beanName);
   }
}

protected void detectHandlerMethods(Object handler) {
    //获取类型
   Class<?> handlerType = (handler instanceof String ?
         obtainApplicationContext().getType((String) handler) : handler.getClass());

   if (handlerType != null) {
      Class<?> userType = ClassUtils.getUserClass(handlerType);
      Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
            (MethodIntrospector.MetadataLookup<T>) method -> {
               try {
               //这里会把RequestMapping转换为RequestMappingInfo
                  return getMappingForMethod(method, userType);
               }
               catch (Throwable ex) {
                  throw new IllegalStateException("Invalid mapping on handler class [" +
                        userType.getName() + "]: " + method, ex);
               }
            });
      if (logger.isTraceEnabled()) {
         logger.trace(formatMappings(userType, methods));
      }
      methods.forEach((method, mapping) -> {
         Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
         //注册到mappingRegistry中,后面会根据request获取对应的HandlerMethod
         registerHandlerMethod(handler, invocableMethod, mapping);
      });
   }
}
复制代码

RequestMapping转换为RequestMappingInfo

@Override
@Nullable
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    //获取方法上的RequestMapping并且转换为RequestMappingInfo
   RequestMappingInfo info = createRequestMappingInfo(method);
   if (info != null) {
       //获取类上的RequestMapping并且转换为RequestMappingInfo(这里就是Controller上的RequestMapping)
      RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
      if (typeInfo != null) {
          //将方法上的RequestMapping和类上的RequestMapping合并,这里会合并url
         info = typeInfo.combine(info);
      }
      String prefix = getPathPrefix(handlerType);
      if (prefix != null) {
         info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
      }
   }
   return info;
}
复制代码

这个方法会把方法上的RequestMapping转换为RequestMappingInfo,把类上的RequestMapping转换为RequestMappingInfo,然后再把两个RequestMappingInfo合并成一个(url的合并)。

HandlerMethod的注册

protected void registerHandlerMethod(Object handler, Method method, T mapping) {
   //这里直接注册到mappingRegistry中,后面也直接从mappingRegistry获取
   this.mappingRegistry.register(mapping, handler, method);
}

public void register(T mapping, Object handler, Method method) {
   if (KotlinDetector.isKotlinType(method.getDeclaringClass())) {
      Class<?>[] parameterTypes = method.getParameterTypes();
      if ((parameterTypes.length > 0) && "kotlin.coroutines.Continuation".equals(parameterTypes[parameterTypes.length - 1].getName())) {
         throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
      }
   }
   this.readWriteLock.writeLock().lock();
   try {
       //创建HandlerMethod
      HandlerMethod handlerMethod = createHandlerMethod(handler, method);
      validateMethodMapping(handlerMethod, mapping);
      this.mappingLookup.put(mapping, handlerMethod);

      List<String> directUrls = getDirectUrls(mapping);
      for (String url : directUrls) {
         this.urlLookup.add(url, mapping);
      }

      String name = null;
      if (getNamingStrategy() != null) {
         name = getNamingStrategy().getName(handlerMethod, mapping);
         addMappingName(name, handlerMethod);
      }

      CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
      if (corsConfig != null) {
         this.corsLookup.put(handlerMethod, corsConfig);
      }
       //这里会添加到MappingRegistry中去
      this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
   }
   finally {
      this.readWriteLock.writeLock().unlock();
   }
}
复制代码

这里需要注意的是,注册的Controller是直接注册的HandlerMethod,这个HandlerMethod就是对应的Controller类中具体请求对应的方法,这个对象封装了所有信息,后面获取出HandlerMethod后会通过反射调用具体的方法

进入
RequestMappingHandlerMapping的getHandler方法看下,这个方法在父类AbstractHandlerMapping中实现,这里用到了设计模式中的模版方法。

@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    //这里获取真正的处理器,子类AbstractHandlerMethodMapping实现
   Object handler = getHandlerInternal(request);
   if (handler == null) {
      //没有的话,使用默认的
      handler = getDefaultHandler();
   }
   if (handler == null) {
      return null;
   }
   // 如果是beanName的话 从ioc容器中获取真正的实例
   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;
}
复制代码

这里核心关注两个方法,一个是获取处理器的getHandlerInternal方法,一个是获取对应拦截器链的getHandlerExecutionChain方法

AbstractHandlerMethodMapping的getHandlerInternal方法

@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
   String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
   request.setAttribute(LOOKUP_PATH, lookupPath);
   this.mappingRegistry.acquireReadLock();
   try {
      HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
      return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
   }
   finally {
      this.mappingRegistry.releaseReadLock();
   }
}

@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
   List<Match> matches = new ArrayList<>();
   List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
   if (directPathMatches != null) {
      addMatchingMappings(directPathMatches, matches, request);
   }
   if (matches.isEmpty()) {
      // No choice but to go through all mappings...
      addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
   }

   if (!matches.isEmpty()) {
      Match bestMatch = matches.get(0);
      if (matches.size() > 1) {
         Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
         matches.sort(comparator);
         bestMatch = matches.get(0);
         if (logger.isTraceEnabled()) {
            logger.trace(matches.size() + " matching mappings: " + matches);
         }
         if (CorsUtils.isPreFlightRequest(request)) {
            return PREFLIGHT_AMBIGUOUS_MATCH;
         }
         Match secondBestMatch = matches.get(1);
         if (comparator.compare(bestMatch, secondBestMatch) == 0) {
            Method m1 = bestMatch.handlerMethod.getMethod();
            Method m2 = secondBestMatch.handlerMethod.getMethod();
            String uri = request.getRequestURI();
            throw new IllegalStateException(
                  "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
         }
      }
      request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
      handleMatch(bestMatch.mapping, lookupPath, request);
      return bestMatch.handlerMethod;
   }
   else {
      return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
   }
}
复制代码

从上面的方法中可以看出,最后是从mappingRegistry属性中取出的HandlerMethod,mappingRegistry在上面的
RequestMappingHandlerMapping中有详细讲解

AbstractHandlerMapping的getHandlerExecutionChain方法

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;
}
复制代码

到这就已经拿到了对应的拦截器链和响应请求对应的方法了。接下来就是调用方法了,这里就轮到HandlerAdapter出场了,如何获取
RequestMappingHandlerAdapter的方法getHandlerAdapter这里就跳过了

再回到DispatchServlet的doDispatch方法中的

//这里的ha就是RequestMappingHandlerAdapter类
//核心是RequestMappingHandlerAdapter类的handleInternal方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
复制代码

RequestMappingHandlerAdapter类的handleInternal方法

@Override
protected ModelAndView handleInternal(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

   ModelAndView mav;
   checkRequest(request);

   if (this.synchronizeOnSession) {
      HttpSession session = request.getSession(false);
      if (session != null) {
         Object mutex = WebUtils.getSessionMutex(session);
         synchronized (mutex) {
            //这里就是真正调用HandlerMethod的地方了
            mav = invokeHandlerMethod(request, response, handlerMethod);
         }
      }
      else {
          //这里就是真正调用HandlerMethod的地方了
         mav = invokeHandlerMethod(request, response, handlerMethod);
      }
   }
   else {
    //这里就是真正调用HandlerMethod的地方了
      mav = invokeHandlerMethod(request, response, handlerMethod);
   }

   if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
      if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
         applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
      }
      else {
         prepareResponse(response);
      }
   }

   return mav;
}
复制代码

到这里,整个调用的过程就已经到此为止了。其中的HandlerAdapter的注册、获取、处理请求反射调用HandlerMethod等以后的章节再分析。

链接:
https://juejin.cn/post/7026266185729572872

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>