Spring MVC RequestMapping 原理

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Spring MVC RequestMapping 原理

RequestMapping 原理


  • spring-webmvc-4.3.7.RELEASE

SpringMVC 启动的时候,会加载 加了注解 @Controller 的 Bean.

栗子:

@Controller
@RequestMapping("/test")
public class TestController {
    @RequestMapping(value = {"/show"})
    public String testTest() {
        return "/jsp/index";
    }
}
  • @Controller 注解, 它标记的类就是一个 SpringMVC Controller对象,分发处理器会扫描使用该注解的类的方法,并检测该方法是否使用了@RequestMapping注解。
  • @RequestMapping注解用来把web请求映射到相应的处理函数。

@Controller和@RequestMapping结合起来完成了Spring MVC请求的派发流程。


@RequestMapping 处理流程


  1. 注册RequestMappingHandlerMapping bean.
  2. 实例化 RequestMappingHandlerMapping bean.
  3. 获取 RequestMappingHandlerMaping bean 实例.
  4. 接收 Request 请求
  5. 在 RequestMappingHandlerMapping 实例中查找对应的 Handler
  6. handler 处理请求。


RequestMappingHandlerMapping  是如何实例化的


简述:new 出来的,带有父类 AbstractHandlerMethodMapping 属性 mappingRegistry , mappingRegistry key value 中的 value 指的是 带有  requestMapping 注解的方法 。

如果想要 RequestMapping 注解生效,必须在 xml 文件中配置,< mvc:annotation-driven/>。

配置完 xml 之后 ,下一步解析 bean。


protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        //如果该元素属于默认命名空间走此逻辑。Spring的默认namespace为:http://www.springframework.org/schema/beans“
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                     //对document中的每个元素都判断其所属命名空间,然后走相应的解析逻辑
                    if (delegate.isDefaultNamespace(ele)) {
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            //如果该元素属于自定义namespace走此逻辑 ,比如AOP,MVC等。
            delegate.parseCustomElement(root);
        }
    }


beans 等默认命名空间执行 parseDefaultElement() 方法,其他命名空间执行 parseCustomElement() 方法.


public BeanDefinition parseCustomElement(Element ele) {
        return parseCustomElement(ele, null);
    }


进入parseCustomElement(ele, null)方法。


public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
        //获取该元素namespace url
        String namespaceUri = getNamespaceURI(ele);
        //得到NamespaceHandlerSupport实现类解析元素
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler == null) {
            error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
            return null;
        }
        return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    }


进入NamespaceHandlerSupport类的parse()方法。


public BeanDefinition parse(Element element, ParserContext parserContext) {
        //此处得到AnnotationDrivenBeanDefinitionParser类来解析该元素
        return findParserForElement(element, parserContext).parse(element, parserContext);
    }


  1. 获取元素的解析类
  2. 解析元素

获取解析类


private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
        String localName = parserContext.getDelegate().getLocalName(element);
        BeanDefinitionParser parser = this.parsers.get(localName);
        if (parser == null) {
            parserContext.getReaderContext().fatal(
                    "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
        }
        return parser;
    }


解析< mvc:annotation-driven/>元素 进入AnnotationDrivenBeanDefinitionParser类的parse()方法。

注解解析器处理


public BeanDefinition parse(Element element, ParserContext parserContext) {
        Object source = parserContext.extractSource(element);
        XmlReaderContext readerContext = parserContext.getReaderContext();
        CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source);
        parserContext.pushContainingComponent(compDefinition);
        RuntimeBeanReference contentNegotiationManager = getContentNegotiationManager(element, source, parserContext);
        //生成RequestMappingHandlerMapping bean信息
        RootBeanDefinition handlerMappingDef = new RootBeanDefinition(RequestMappingHandlerMapping.class);
        handlerMappingDef.setSource(source);
        handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        handlerMappingDef.getPropertyValues().add("order", 0);
        handlerMappingDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
        ......
        //此处HANDLER_MAPPING_BEAN_NAME值为:RequestMappingHandlerMapping类名
        //容器中注册name为RequestMappingHandlerMapping类名
        parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
        ......
    }


Spring 容器中注册了一个名为 “HANDLER_MAPPING_BEAN_NAME”,类型为 RequestMappingHandlerMapping.

RequestMappingHandlerMapping 实例化

RequestMappingHandlerMapping 继承图


image.png

RequestMappingHandlerMapping实现了 HandlerMapping 接口,同时还实现了 ApplicationContectAware 和 IntialingBean 接口。

ApplicationContextAware

这个接口只包含以下方法:


void setApplicationContext(ApplicationContext applicationContext) throws BeansException;


如果一个类实现了 ApplicationContextAware 接口,Spring容器在初始化该类时候会自动回调该类的setApplicationContext()方法。这个接口主要用来让实现类得到Spring 容器上下文信息。


initializingBean 接口

这个接口包含下面方法:

void afterPropertiesSet() throws Exception;


如果一个bean实现了该接口,Spring 容器初始化bean时会回调afterPropertiesSet()方法。这个接口的主要作用是让bean在初始化时可以实现一些自定义的操作。


RequestMappingHandlerMapping 源码分析


RequestMappingHandlerMapping 实现了 ApplicationContextAware 接口 , 那么实例化后会执行 setApplicationContext 方法


@Override
 public final void setApplicationContext(@Nullable ApplicationContext context) throws BeansException {
  if (context == null && !isContextRequired()) {
   // Reset internal context state.
   this.applicationContext = null;
   this.messageSourceAccessor = null;
  }
  else if (this.applicationContext == null) {
   // Initialize with passed-in context.
   if (!requiredContextClass().isInstance(context)) {
    throw new ApplicationContextException(
      "Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
   }
   this.applicationContext = context;
   this.messageSourceAccessor = new MessageSourceAccessor(context);
   initApplicationContext(context);
  }
  else {
   // Ignore reinitialization if same context passed in.
   if (this.applicationContext != context) {
    throw new ApplicationContextException(
      "Cannot reinitialize with different application context: current one is [" +
      this.applicationContext + "], passed-in one is [" + context + "]");
   }
  }
 }


这个方法把容器上下文赋值给 applicationContext 变量,赋值的就是 spring mvc 容器。

RequestMappingHandlerMapping 实现了 InitializingBean 接口。设置完属性后回调 afterpropertiesSet 方法.


public void afterPropertiesSet() {
  this.config = new RequestMappingInfo.BuilderConfiguration();
  this.config.setTrailingSlashMatch(useTrailingSlashMatch());
  this.config.setContentNegotiationManager(getContentNegotiationManager());
  if (getPatternParser() != null) {
   this.config.setPatternParser(getPatternParser());
   Assert.isTrue(!this.useSuffixPatternMatch && !this.useRegisteredSuffixPatternMatch,
     "Suffix pattern matching not supported with PathPatternParser.");
  }
  else {
   this.config.setSuffixPatternMatch(useSuffixPatternMatch());
   this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
   this.config.setPathMatcher(getPathMatcher());
  }
  super.afterPropertiesSet();
 }


同时还调用了父类的 afterPropertiesSet 方法


public void afterPropertiesSet() {
        //初始化handler函数
        initHandlerMethods();
    }


继续查看 RequestMappingHandlerMapping.initHandlerMethods 方法


protected void initHandlerMethods() {
        if (logger.isDebugEnabled()) {
            logger.debug("Looking for request mappings in application context: " + getApplicationContext());
        }
        //1.获取容器中所有bean 的name。
        //根据detectHandlerMethodsInAncestorContexts bool变量的值判断是否获取父容器中的bean,默认为false。因此这里只获取Spring MVC容器中的bean,不去查找父容器
        String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
                BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
                getApplicationContext().getBeanNamesForType(Object.class));
        //循环遍历bean
        for (String beanName : beanNames) {
            if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
                Class<?> beanType = null;
                try {
                    beanType = getApplicationContext().getType(beanName);
                }
                catch (Throwable ex) {
                    // An unresolvable bean type, probably from a lazy bean - let's ignore it.
                    if (logger.isDebugEnabled()) {
                        logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
                    }
                }
                //2.判断bean是否含有@Controller或者@RequestMappin注解
                if (beanType != null && isHandler(beanType)) {
                    //3.对含有注解的bean进行处理,获取handler函数信息。
                    detectHandlerMethods(beanName);
                }
            }
        }
        handlerMethodsInitialized(getHandlerMethods());
    }


可以看出 RequestMappingHandlerMapping.initHandlerMethods 方法进行了如下操作:

  1. 获取Spring MVC 中的 bean
  2. 找出 含义 @Controller 和 @RequestMapping 的注解
  3. 对含义注解 bean 进行解析

查看 RequestMappingHandlerMapping.isHandle 处理逻辑


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


看对含义 Controller 和 RequestMapping 的怎么处理

查看 RequestMappingHandlerMapping.detectHandlerMethods 方法


protected void detectHandlerMethods(final Object handler) {
        //1.获取bean的类信息
        Class<?> handlerType = (handler instanceof String ?
                getApplicationContext().getType((String) handler) : handler.getClass());
        final Class<?> userType = ClassUtils.getUserClass(handlerType);
        //2.遍历函数获取有@RequestMapping注解的函数信息
        Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
                new MethodIntrospector.MetadataLookup<T>() {
                    @Override
                    public T inspect(Method method) {
                        try {
                            //如果有@RequestMapping注解,则获取函数映射信息
                            return getMappingForMethod(method, userType);
                        }
                        catch (Throwable ex) {
                            throw new IllegalStateException("Invalid mapping on handler class [" +
                                    userType.getName() + "]: " + method, ex);
                        }
                    }
                });
        if (logger.isDebugEnabled()) {
            logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
        }
        //3.遍历映射函数列表,注册handler
        for (Map.Entry<Method, T> entry : methods.entrySet()) {
            Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
            T mapping = entry.getValue();
            //注册handler函数
            registerHandlerMethod(handler, invocableMethod, mapping);
        }
    };


detectHandlerMethods 主要功能就是获取该bean和父接口中所有用@RequestMapping注解的函数信息,并把这些保存到methodMap变量中。

查看  RequestMappingHandlerMapping.selectMethods 方法实现逻辑


public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
        final Map<Method, T> methodMap = new LinkedHashMap<Method, T>();
        Set<Class<?>> handlerTypes = new LinkedHashSet<Class<?>>();
        Class<?> specificHandlerType = null;
        //把自身类添加到handlerTypes中
        if (!Proxy.isProxyClass(targetType)) {
            handlerTypes.add(targetType);
            specificHandlerType = targetType;
        }
        //获取该bean所有的接口,并添加到handlerTypes中
        handlerTypes.addAll(Arrays.asList(targetType.getInterfaces()));
        /对自己及所有实现接口类进行遍历
        for (Class<?> currentHandlerType : handlerTypes) {
            final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
            //获取函数映射信息
            ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
                //循环获取类中的每个函数,通过回调处理
                @Override
                public void doWith(Method method) {
                    //对类中的每个函数进行处理
                    Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
                    //回调inspect()方法给个函数生成RequestMappingInfo  
                    T result = metadataLookup.inspect(specificMethod);
                    if (result != null) {
                        Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
                        if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
                            //将生成的RequestMappingInfo保存到methodMap中
                            methodMap.put(specificMethod, result);
                        }
                    }
                }
            }, ReflectionUtils.USER_DECLARED_METHODS);
        }
        //返回保存函数映射信息后的methodMap
        return methodMap;
    }


上面逻辑中doWith()回调了inspect(),inspect()又回调了getMappingForMethod()方法。

我们看看getMappingForMethod()是如何生成函数信息的。


@Override
    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        //创建函数信息
        RequestMappingInfo info = createRequestMappingInfo(method);
        if (info != null) {
            RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
            if (typeInfo != null) {
                info = typeInfo.combine(info);
            }
        }
        return info;
    }


查看RequestMappingHandlerMapping#createRequestMappingInfo()方法。


private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
        //如果该函数含有@RequestMapping注解,则根据其注解信息生成RequestMapping实例,
        //如果该函数没有@RequestMapping注解则返回空
        RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
        RequestCondition<?> condition = (element instanceof Class ?
                getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
        //如果requestMapping不为空,则生成函数信息MAP后返回
        return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
    }


看看RequestMappingHandlerMapping#createRequestMappingInfo是如何实现的。


protected RequestMappingInfo createRequestMappingInfo(
            RequestMapping requestMapping, RequestCondition<?> customCondition) {
        return RequestMappingInfo
                .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
                .methods(requestMapping.method())
                .params(requestMapping.params())
                .headers(requestMapping.headers())
                .consumes(requestMapping.consumes())
                .produces(requestMapping.produces())
                .mappingName(requestMapping.name())
                .customCondition(customCondition)
                .options(this.config)
                .build();


可以看到上面把RequestMapping注解中的信息都放到一个RequestMappingInfo实例中后返回。当生成含有@RequestMapping注解的函数映射信息后,最后一步是调用registerHandlerMethod 注册handler和处理函数映射关系。


protectedvoid registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
   }


看到把所有的handler方法都注册到了mappingRegistry这个变量中。

到此就把RequestMappingHandlerMapping bean的实例化流程就分析完了。

Spring MVC容器初始化流程,查看在 FrameworkServlet#initWebApplicationContext 方法。


protected WebApplicationContext initWebApplicationContext() {
        //1.获得rootWebApplicationContext
        WebApplicationContext rootContext =
                WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;
        ......
        if (wac == null) {
            // No context instance is defined for this servlet -> create a local one
            //2.创建 Spring 容器 
            wac = createWebApplicationContext(rootContext);
        }
        if (!this.refreshEventReceived) {
            // Either the context is not a ConfigurableApplicationContext with refresh
            // support or the context injected at construction time had already been
            // refreshed -> trigger initial onRefresh manually here.
            //3.初始化容器
            onRefresh(wac);
        }
        ......
        return wac;
    }


查看 DispatchServlet#onRefresh 方法


@Override
    protected void onRefresh(ApplicationContext context) {
        //执行初始化策略 
        initStrategies(context);
    }


查看 initStrategies 方法


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


查看  initHandlerMappings 方法


private void initHandlerMappings(ApplicationContext context) {
        this.handlerMappings = null;
        if (this.detectAllHandlerMappings) {
            // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
            //容器中查找HandlerMapping的实例
            Map<String, HandlerMapping> matchingBeans =
                    BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
            if (!matchingBeans.isEmpty()) {
                //把找到的bean放到hanlderMappings中。
                this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
                // We keep HandlerMappings in sorted order.
                AnnotationAwareOrderComparator.sort(this.handlerMappings);
            }
        }
        else {
            try {
                HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
                this.handlerMappings = Collections.singletonList(hm);
            }
            catch (NoSuchBeanDefinitionException ex) {
                // Ignore, we'll add a default HandlerMapping later.
            }
        }
        // Ensure we have at least one HandlerMapping, by registering
        // a default HandlerMapping if no other mappings are found.
        if (this.handlerMappings == null) {
            this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
            if (logger.isDebugEnabled()) {
                logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
            }
        }
    }


最终是 实例化的  RequestMappingHandlerMapping  放到了一个 HandlerMapping 中。

服务请求是怎么处理的?


DispatchServlet 继承自Servlet,那所有的请求都会在service()方法中进行处理。

查看service()方法。

@Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //获取请求方法
        HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
        //若是patch请求执行此逻辑
        if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
            processRequest(request, response);
        }
        else {
            //其它请求走此逻辑
            super.service(request, response);
        }
    }


protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
  if (logger.isDebugEnabled()) {
   String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
   logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
     " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
  }
  // Keep a snapshot of the request attributes in case of an include,
  // to be able to restore the original attributes after the include.
  Map<String, Object> attributesSnapshot = null;
  if (WebUtils.isIncludeRequest(request)) {
   attributesSnapshot = new HashMap<String, Object>();
   Enumeration<?> attrNames = request.getAttributeNames();
   while (attrNames.hasMoreElements()) {
    String attrName = (String) attrNames.nextElement();
    if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
     attributesSnapshot.put(attrName, request.getAttribute(attrName));
    }
   }
  }
  // Make framework objects available to handlers and view objects.
  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());
  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()) {
    // Restore the original attribute snapshot, in case of an include.
    if (attributesSnapshot != null) {
     restoreAttributesAfterInclude(request, attributesSnapshot);
    }
   }
  }
 }

得到不管get、post最后都会执行到DispatcherServlet#doDispatch(request, response);

查看 doDispatch 方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  HttpServletRequest processedRequest = request;
  HandlerExecutionChain mappedHandler = null;
  boolean multipartRequestParsed = false;
  WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  try {
   ModelAndView mv = null;
   Exception dispatchException = null;
   try {
    processedRequest = checkMultipart(request);
    multipartRequestParsed = (processedRequest != request);
    // Determine handler for the current request.
    mappedHandler = getHandler(processedRequest);
    if (mappedHandler == null || mappedHandler.getHandler() == 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 (logger.isDebugEnabled()) {
      logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
     }
     if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
      return;
     }
    }
    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
     return;
    }
    // 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;
   }
   processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
  }
  catch (Exception ex) {
   triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
  }
  catch (Error err) {
   triggerAfterCompletionWithError(processedRequest, response, mappedHandler, 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);
    }
   }
  }
 }


查看 mappedHandler = getHandler(processedRequest); 方法


protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //获取HandlerMapping实例
        for (HandlerMapping hm : this.handlerMappings) {
            if (logger.isTraceEnabled()) {
                logger.trace(
                        "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
            }
             //得到处理请求的handler
            HandlerExecutionChain handler = hm.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
        return null;
    }


上面遍历handlerMappings获得所有HandlerMapping实例,还记得handlerMappings变量吧,这就是前面initHandlerMappings()方法中设置进去的值,其实就是为了找到 RequestMappingHandlerMapping。


@Override
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        Object handler = getHandlerInternal(request);
        ......
        HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
        ......
        return executionChain;
    }


进入 AbstractHandlerMethodMapping#getHandlerInternal 方法


@Override
    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
        //获取函数url
        String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
        ......
        try {
            //查找HandlerMethod 
            HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
            ......
        }
        finally {
            this.mappingRegistry.releaseReadLock();
        }
    }


进入 lookupHandlerMethod 方法


protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
        List<Match> matches = new ArrayList<Match>();
        List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
        ......
    }


最后从 mappingRegistry 找到对应的处理方法 这个 mappingRegistry 就是来自 实例化后的 RequestMappingHandlerMapping 。


总结


在初始化容器时,会 new 一个RequestMappingHandlerMapping,其父类是AbstractHandlerMethodMapping 。并把这个RequestMappingHandlerMapping 放到一个 HandlerMapping 中。

实例化后带有属性 mappingRegistry , mappingRegistry 的 value 指的是带有 requestMapping 注解的方法。

在服务请求时,遍历 HandlerMapping ,并根据请求信息,从RequestMappingHandlerMapping 中找到对应的处理方法handler

相关文章
|
7天前
|
XML Java 开发者
Spring Boot开箱即用可插拔实现过程演练与原理剖析
【11月更文挑战第20天】Spring Boot是一个基于Spring框架的项目,其设计目的是简化Spring应用的初始搭建以及开发过程。Spring Boot通过提供约定优于配置的理念,减少了大量的XML配置和手动设置,使得开发者能够更专注于业务逻辑的实现。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,为开发者提供一个全面的理解。
18 0
|
1月前
|
Java Spring 容器
Spring底层原理大致脉络
Spring底层原理大致脉络
|
1月前
|
JSON 前端开发 Java
SSM:SpringMVC
本文介绍了SpringMVC的依赖配置、请求参数处理、注解开发、JSON处理、拦截器、文件上传下载以及相关注意事项。首先,需要在`pom.xml`中添加必要的依赖,包括Servlet、JSTL、Spring Web MVC等。接着,在`web.xml`中配置DispatcherServlet,并设置Spring MVC的相关配置,如组件扫描、默认Servlet处理器等。然后,通过`@RequestMapping`等注解处理请求参数,使用`@ResponseBody`返回JSON数据。此外,还介绍了如何创建和配置拦截器、文件上传下载的功能,并强调了JSP文件的放置位置,避免404错误。
|
1月前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
128 9
|
1月前
|
前端开发 Java 应用服务中间件
【Spring】Spring MVC的项目准备和连接建立
【Spring】Spring MVC的项目准备和连接建立
57 2
|
2月前
|
缓存 前端开发 Java
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
Soring Boot的起步依赖、启动流程、自动装配、常用的注解、Spring MVC的执行流程、对MVC的理解、RestFull风格、为什么service层要写接口、MyBatis的缓存机制、$和#有什么区别、resultType和resultMap区别、cookie和session的区别是什么?session的工作原理
【Java面试题汇总】Spring,SpringBoot,SpringMVC,Mybatis,JavaWeb篇(2023版)
|
1月前
|
XML 前端开发 Java
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
本文阐述了Spring、Spring Boot和Spring MVC的关系与区别,指出Spring是一个轻量级、一站式、模块化的应用程序开发框架,Spring MVC是Spring的一个子框架,专注于Web应用和网络接口开发,而Spring Boot则是对Spring的封装,用于简化Spring应用的开发。
119 0
Spring,SpringBoot和SpringMVC的关系以及区别 —— 超准确,可当面试题!!!也可供零基础学习
|
2月前
|
XML 缓存 前端开发
springMVC02,restful风格,请求转发和重定向
文章介绍了RESTful风格的基本概念和特点,并展示了如何使用SpringMVC实现RESTful风格的请求处理。同时,文章还讨论了SpringMVC中的请求转发和重定向的实现方式,并通过具体代码示例进行了说明。
springMVC02,restful风格,请求转发和重定向
|
1月前
|
XML 前端开发 Java
拼多多1面:聊聊Spring MVC的工作原理!
本文详细剖析了Spring MVC的工作原理,涵盖其架构、工作流程及核心组件。Spring MVC采用MVC设计模式,通过DispatcherServlet、HandlerMapping、Controller和ViewResolver等组件高效处理Web请求。文章还探讨了DispatcherServlet的初始化和请求处理流程,以及HandlerMapping和Controller的角色。通过理解这些核心概念,开发者能更好地构建可维护、可扩展的Web应用。适合面试准备和技术深挖
43 0
|
1月前
|
负载均衡 Java API
Spring Cloud原理详解
Spring Cloud原理详解
69 0