DEV Community

Salad Lam
Salad Lam

Posted on

Spring MVC: how framework maps URI to bean

Notice

I wrote this article and was originally published on Qiita on 1 July 2021.


What is org.springframework.web.servlet.HandlerMapping interface?

From the document from Spring Framework, it says "Interface to be implemented by objects that define a mapping between requests and handler objects.". In my notice board example application, following bean is created when started.

Order Bean Name Class Where it created
2147483647 welcomePageHandlerMapping org.springframework.boot.autoconfigure.web.servlet.WelcomePageHandlerMapping org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.EnableWebMvcConfiguration.welcomePageHandlerMapping(ApplicationContext, FormattingConversionService, ResourceUrlProvider)
2147483646 resourceHandlerMapping org.springframework.web.servlet.handler.SimpleUrlHandlerMapping org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.resourceHandlerMapping()
2 beanNameHandlerMapping org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport.beanNameHandlerMapping()
0 requestMappingHandlerMapping org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.EnableWebMvcConfiguration.requestMappingHandlerMapping()
-2147483647 faviconHandlerMapping org.springframework.web.servlet.handler.SimpleUrlHandlerMapping org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter.FaviconConfiguration.faviconHandlerMapping()

requestMappingHandlerMapping handles bean class which have org.springframework.web.bind.annotation.RequestMapping annotation.

How I know this? Please refer to here.

When it been loaded

First, beans are created by ApplicationContext instance.

Then when org.springframework.web.servlet.DispatcherServlet instance is created and during initialization, org.springframework.web.servlet.DispatcherServlet.initHandlerMappings(ApplicationContext) is called and all bean with org.springframework.web.servlet.HandlerMapping interface will been lookup. Its reference will be saved into DispatcherServlet's internal structure. Following is related code.

/**
 * Initialize the HandlerMappings used by this class.
 * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
 * we default to BeanNameUrlHandlerMapping.
 */
private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;

    if (this.detectAllHandlerMappings) {
        // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
        Map<String, HandlerMapping> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            // We keep HandlerMappings in sorted order.
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    }
    else {
        ...
    }
    ...
}
Enter fullscreen mode Exit fullscreen mode

Look up which bean handles particular URI

In method org.springframework.web.servlet.DispatcherServlet.doDispatch(HttpServletRequest, HttpServletResponse) you can see how Spring MVC actually handle a request. The code which lookup URI bean mapping is

mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
    noHandlerFound(processedRequest, response);
    return;
}
Enter fullscreen mode Exit fullscreen mode

And in method org.springframework.web.servlet.DispatcherServlet.getHandler(HttpServletRequest), request will be passed into list of instances with org.springframework.web.servlet.HandlerMapping interface which is built before. If mapping is found in one instance, lookup will be stopped and org.springframework.web.servlet.HandlerExecutionChain will be returned. Following is the code.

/**
 * Return the HandlerExecutionChain for this request.
 * <p>Tries all handler mappings in order.
 * @param request current HTTP request
 * @return the HandlerExecutionChain, or {@code null} if no handler could be found
 */
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}
Enter fullscreen mode Exit fullscreen mode

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (0)

AWS GenAI LIVE image

Real challenges. Real solutions. Real talk.

From technical discussions to philosophical debates, AWS and AWS Partners examine the impact and evolution of gen AI.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay