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

Top comments (0)