Spring MVC: how framework maps URI to bean
Tags: spring, springmvc
Published: 2024-01-31 21:34:16

## Notice

I wrote this article and was originally published on [Qiita](https://qiita.com/saladlam/items/48fbffe0273211d2b237) 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](https://github.com/saladlam/spring-noticeboard), 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](https://www.logicbig.com/tutorials/spring-framework/spring-web-mvc/handler-mapping.html).

# 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.

```java
/**
 * 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 {
		...
	}
	...
}
```

# 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

```java
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
	noHandlerFound(processedRequest, response);
	return;
}
```

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.

```java
/**
 * 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;
}
```