学习笔记之SpringMVC前端控制器及方法映射源码分析

本文深入剖析SpringMVC的工作原理,从DispatcherServlet的初始化、请求处理流程到HandlerMapping的匹配策略,详细解读了SpringMVC如何处理HTTP请求,以及RequestMappingHandlerMapping如何注册和匹配处理器方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring MVC前端控制器及方法映射源码分析

(个人学习笔记,如有错误欢迎指正!!!)

前端控制器(DispatcherServlet)

DispatcherServlet<FrameworkServlet<HttpServletBean<HttpServlet

首先 DispatcherServlet是一个 Servlet,所以基本的流程为 init()->service()->destory()

init()过程是是现在父类 HttpServletBean中:

public final void init() throws ServletException {
   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();
}

首先是读取 <init-param>的配置元素,配置相关的bean,之后调用 initServletBean()方法来创建Servlet WebApplicationContextinitServletBean()被子类 FrameworkServlet重写了:

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 {
      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");
   }
}

主要的作用就是创建一个 WebApplicationContextinitFrameworkServlet()的实现为空。

DispatcherServlet在相应请求时,调用的时父类 FrameworkServletservice()方法:

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

该方法主要是判断请求方法是否为 patch或者为 null,如果是则调用 processRequest(request, response),否则调用父类 HttpServlet中的 service()方法,该方法会根据请求类型调用相应的 doGet,doPost等方法,FrameworkServlet重写了这些方法,最终均会调用 processRequest(request, response)方法。

protected final void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

   processRequest(request, response);
}

processRequest(request, response)方法中,先将获取到的相关信息通过 initContextHolders 方法绑定到线程上,再调用 doService()方法(该方法由 DispatcherServlet实现),最后调用 resetContextHolders方法解除相关信息与线程的绑定。

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
	......
   initContextHolders(request, localeContext, requestAttributes);
   try {
      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);
	......
}

doService()方法中主要调用 doDispatch()

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
   ......
   try {
      doDispatch(request, response);
   }
   finally {
   ......
}

首先判断是否为 Multipart请求类型,如果是便通过 multipartResolver来解析请求

通过getHandler方法找到从HandlerMapping找到该请求对应的handler,如果没有找到对应的handler则抛出异常。

通过getHandlerAdapter方法找到handler对应的HandlerAdapter

如果有拦截器,执行拦截器preHandler方法

HandlerAdapter执行handle方法处理请求,返回ModelAndView

如果有拦截器,执行拦截器postHandle方法

然后调用processDispatchResult方法处理请求结果,封装到response中。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   		......
      try {
         processedRequest = checkMultipart(request);
         multipartRequestParsed = (processedRequest != request);

         // Determine handler for the current request.
         mappedHandler = getHandler(processedRequest);
         if (mappedHandler == null) {
            noHandlerFound(processedRequest, response);
            return;
         }

         // Determine handler adapter for the current request.
         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.
         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) {
         dispatchException = new NestedServletException("Handler dispatch failed", err);
      }
      processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
   	  ......
}

HandlerMapping 映射处理

RequestMappingHandlerMapping是Spring MVC中的内置Bean,会自动进行加载,同时该类还实现了 InitializingBean接口,该接口提供了 afterPropertiesSet() 方法,该方法会在bean初始化的时候执行,

public interface InitializingBean {
   void afterPropertiesSet() throws Exception;
}

该方法是在 AbstractAutowireCapableBeanFactory.invokeInitMethods()方法中调用,该方法会在初始化bean的时候调用,该方法首先判断这个bean是不是 InitializingBean接口的实例,如果是便调用 afterPropertiesSet()方法。

protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
      throws Throwable {

   boolean isInitializingBean = (bean instanceof InitializingBean);
   if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
      if (logger.isTraceEnabled()) {
         logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
      }
      if (System.getSecurityManager() != null) {
         try {
            AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
               ((InitializingBean) bean).afterPropertiesSet();
               return null;
            }, getAccessControlContext());
         }
         catch (PrivilegedActionException pae) {
            throw pae.getException();
         }
      }
      else {
         ((InitializingBean) bean).afterPropertiesSet();
      }
   }

   if (mbd != null && bean.getClass() != NullBean.class) {
      String initMethodName = mbd.getInitMethodName();
      if (StringUtils.hasLength(initMethodName) &&
            !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
            !mbd.isExternallyManagedInitMethod(initMethodName)) {
         invokeCustomInitMethod(beanName, bean, mbd);
      }
   }
}

RequestMappingHandlerMapping -> RequestMappingInfoHandlerMapping -> AbstractHandlerMethodMapping -> InitializingBean

afterPropertiesSet()实现在 AbstractHandlerMethodMapping类中,在该方法中,首先遍历所有的bean,然后调用 isHandler()方法判断是否为controller,最后调用 detectHandlerMethods()方法遍历类中所有的方法。

public void afterPropertiesSet() {
   initHandlerMethods();
}
protected void initHandlerMethods() {
    for (String beanName : getCandidateBeanNames()) {
        if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
            processCandidateBean(beanName);
        }
    }
    handlerMethodsInitialized(getHandlerMethods());
}
protected void processCandidateBean(String beanName) {
    Class<?> beanType = null;
    try {
        beanType = obtainApplicationContext().getType(beanName);
    }
    catch (Throwable ex) {
        // An unresolvable bean type, probably from a lazy bean - let's ignore it.
        if (logger.isTraceEnabled()) {
            logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
        }
    }
    if (beanType != null && isHandler(beanType)) {
        detectHandlerMethods(beanName);
    }
}

isHandler()方法实现在 RequestMappingHandlerMapping中,通过判断类是否有 @Controller@RequestMapping注解来判断该类是不是能够由RequestMappingHandlerMapping处理。

protected boolean isHandler(Class<?> beanType) {
   return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
         AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

下面的方法是遍历controller类中的方法,并且使用 registerHandlerMethod()方法进行注册。

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 {
                  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);
         registerHandlerMethod(handler, invocableMethod, mapping);
      });
   }
}

Spring MVC 项目加载的所有内置bean:

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#0
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#0
org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#0
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#0
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#0
org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#1
org.springframework.web.servlet.handler.MappedInterceptor#0
org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
org.springframework.web.servlet.view.InternalResourceViewResolver#0
org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration
org.springframework.web.socket.server.support.WebSocketHandlerMapping#0
org.springframework.web.socket.server.support.DefaultHandshakeHandler#0
org.springframework.web.socket.server.support.WebSocketHttpRequestHandler#0
org.springframework.web.socket.server.support.WebSocketHandlerMapping#1
org.springframework.web.socket.server.support.DefaultHandshakeHandler#1
org.springframework.web.socket.server.support.WebSocketHttpRequestHandler#1
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor
org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
org.springframework.format.support.FormattingConversionServiceFactoryBean#0
org.springframework.data.redis.listener.RedisMessageListenerContainer#0
org.springframework.remoting.rmi.RmiServiceExporter#0
org.springframework.web.socket.config.annotation.DelegatingWebSocketConfiguration

HandlerMapping 路由匹配

DispatcherServlet接受到request请求之后,遍历所有的 HandlerMapping,并且调用 HandlerMapping.getHandler()方法,该方法实现在父类 AbstractHandlerMapping中,在该方法中,首先根据请求获取相应的处理方法(getHandlerInternal()),然后调用 getHandlerExecutionChain()获得执行链。

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   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 (CorsUtils.isCorsRequest(request)) {
      CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
      CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
      CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
      executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
   }

   return executionChain;
}

getHandlerInternal()实现在 AbstractHandlerMethodMapping中,该方法通过 lookupHandlerMethod()方法获得操作方法。

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

lookupHandlerMethod()方法如下,首先根据路径查找匹配的方法,如果结果为空,就将所有的方法全部加到list中(精确匹配优于模糊匹配),然后根据特别的规则对list中的方法进行排序(优先匹配),找到优先级最高的两个,如果这两个相同,表示冲突并抛出异常,否则返回最好的方法。

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()) {
      Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
      matches.sort(comparator);
      Match bestMatch = matches.get(0);
      if (matches.size() > 1) {
         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);
   }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值