HandlerMapping Overview
The HandlerMapping component parses a Request and finds a Handler that handles the Request, which is generally understood as a method in the Controller.
The HandlerMapping component does two main events.
- when the component is initialized, it registers the Request request and the corresponding Handler, which actually means that the Request and the corresponding Handler exist in a map as a key-value pair.
- parse each Request request and find the corresponding handler in the registered map.
In the SpringMvc source code, HandlerMapping is defined as an interface. In addition to defining several property fields, the interface defines only one getHandler
method.
HandlerMapping class system
As you can see from the above class diagram, the HandlerMapping
component is divided into two families. One family inherits from AbstractHandlerMethodMapping
, and the other family inherits from AbstractUrlHandlerMapping
. Both abstract classes inherit from AbstractHandlerMapping
.
AbstractHandlerMapping
AbstractHandlerMapping
is an abstract class that implements the HandlerMapping interface, and it is a very basic class from which all subclasses of HandlerMapping are inherited. AbstractHandlerMapping
uses the template pattern for the overall design, and each subclass overrides the template methods to achieve the appropriate functionality.
Since AbstractHandlerMappin
abstract class inherits the HandlerMapping
interface, it must implement the getHandler method. In the AbstractHandlerMappin
class, the specific code is as follows.
|
|
Special attention should be paid to the getHandlerInternal(request)
method in the getHandler method, which is a boilerplate method. In the AbstractHandlerMapping
class, the getHandlerInternal(request)
method is just an abstract method that doesn’t do anything. This method is specifically reserved for subclasses of AbstractHandlerMapping
to override and thus implement their own business logic.
AbstractHandlerMapping
also inherits from the WebApplicationObjectSupport
class and overrides the initApplicationContext
method of that parent class.
|
|
In the initApplicationContext method, three methods are defined.
-
extendInterceptors(**this**.interceptors)
extendInterceptors is a template method that gives subclasses an entry point to modify this.interceptors interceptors. -
detectMappedInterceptors(**this**.addedInterceptors)
detectMappedInterceptors method is to add all beans of type MappedInterceptor in Spring MVC to the collection of this.addedInterceptors. -
initInterceptors()
initInterceptors is to initialize the interceptors, add all the interceptors wrapped in the this.interceptors collection to the this.adoptedInterceptors collection.
AbstractHandlerMethodMapping series
AbstractHandlerMethodMapping
AbstractHandlerMethodMapping
is a very important class. In addition to inheriting from AbstractHandlerMapping
abstract class, AbstractHandlerMethodMapping
also implements the InitializingBean
interface.
Handler registration
In Spring if a class implements the InitializingBean
interface, the Spring container will call the afterPropertiesSet method of the bean when it is instantiated.
The AbstractHandlerMethodMapping
class does the initialization and registration work when it overrides the afterPropertiesSet method of the InitializingBean
interface. This is the first step of the HandlerMapping
component, registering the Request request and the corresponding Handler first.
The afterPropertiesSet method of the AbstractHandlerMethodMapping
class is shown in the following code.
You can see that the initHandlerMethods(
) method is called in the afterPropertiesSet method of the AbstractHandlerMethodMapping
class. Looking at the name of the initHandlerMethods()
method, you can see that it actually does the initialization work.
|
|
In the initHandlerMethods()
method, the getCandidateBeanNames
method first gets the names of all the beans in the Spring container. The bean name is passed through the loop to the processCandidateBean(beanName)
method.
The processCandidateBean(beanName)
method does three main things.
- Find the type corresponding to the bean by its name.
- Filter out beans that do not match the criteria by the isHandler method. isHandler method is a template method and the specific logic is implemented in the subclass
RequestMappingHandlerMapping
. isHandler method will only select beans that contain@Controller
and@RequestMapping
annotations. - The corresponding mapping between request request and handler is established by the detectHandlerMethods method.
The detectHandlerMethods
method does two main things.
-
use the
getMappingForMethod
method to find the method with the@RequestMapping
annotation through the handler. InAbstractHandlerMethodMapping
class,getMappingForMethod
method in just an abstract method, the specific implementation is in the subclassRequestMappingHandlerMapping
class, to achieve the specific business logic. -
use the
registerHandlerMethod
method to register the found method. The so-called registration is actually the foundHandlerMothed
into a Map. If the sameHandlerMothed
is registered for a second time, an exception will be thrown.
Handler lookup
In the AbstractHandlerMethodMapping
class, the template method getHandlerInternal
of the parent class AbstractHandlerMapping
is overridden.
|
|
In the getHandlerInternal
method, there are three main events that are done.
- In the
initLookupPath
method, a request is converted into a url. - Then use the
lookupHandlerMethod
method to find the correspondingHandlerMethod
by using the two parameters request and lookupPath. - In the case of finding a
HandlerMethod
object, thecreateWithResolvedBean
method of theHandlerMethod
will be called. This method determines whether thisHandlerMethod
object. If it is of type String, it is just a String. If it is of type String then it is just the name of a bean and the bean will be found in the Spring container based on the name of the bean.
RequestMappingInfoHandlerMapping
The RequestMappingInfoHandlerMapping
class mainly overrides the getMatchingMapping
method of the parent class. getMatchingMapping
method returns a RequestMappingInfo
object that matches various RequestCondition
based on the current request. RequestMappingInfo
object that matches various RequestCondition
.
SpringMVC will get the corresponding Handler based on this RequestMappingInfo
object.
RequestMappingHandlerMapping
Spring MVC container in the initialization of the HandlerMapping
type components, the final initialization of the AbstractHandlerMethodMapping
series of components, is RequestMappingHandlerMapping
.
RequestMappingHandlerMapping
mainly overrides the three methods of the parent class.
-
afterPropertiesSet
The
initialization
method of the parent class is overridden and an object of typeBuilderConfiguration
is created in theafterPropertiesSet
method. Then for theBuilderConfiguration
object, the properties are set. -
isHandler
The main purpose is to determine what type of Handler to get, and to play a filtering role on the Handler, only take the
@Controller
and@RequestMapping
two annotated types of Handler. -
getMappingForMethod
The getMappingForMethod
method is mainly used to create the corresponding RequestMappingInfo
object by method. The program first gets the RequestMapping
annotation from the method object. From the RequestMapping
annotation information, it creates “PathMapping”, “HeaderMapping”, “RequestParameterMapping”, “MIMEMapping”, “MIMEMapping”, “MIMEMapping”, and “MIMEMapping”. “MIME matchable”, “MIME matchable”, “request method matchable”, and other RequestCondition
interface instances. Finally these RequestCondition
interface instances are combined to create a RequestMappingInfo
object and SpringMVC registers the request and Handler mapping relationship based on the RequestMappingInfo
object.
The RequestMappingInfo
object implements the RequestCondition
interface. The interface RequestCondition
is Spring MVC’s conceptual modeling of a request matching condition.
AbstractUrlHandlerMapping series
AbstractUrlHandlerMapping
series can be seen from the name, it mainly deals with the relationship between url and handler.
The AbstractUrlHandlerMapping
class firstly puts the mapping relationship between url and handler into a Map, and then gets the corresponding handler by url.
AbstractUrlHandlerMapping
AbstractUrlHandlerMapping
class, like AbstractHandlerMethodMapping
class, also inherits AbstractHandlerMapping
abstract class. All url and HandlerMapping
related subclasses are inherited from the AbstractUrlHandlerMapping
parent class.
AbstractUrlHandlerMapping
also implements the MatchableHandlerMapping
interface, which defines a match method for matching.
HandlerMap registration
In AbstractUrlHandlerMapping
class, the method registerHandler is specifically responsible for registering the handler.
Handler registration is actually storing the url and the corresponding handler in the hash map called handlerMap.
|
|
In the registerHandler method, there are 4 main things done.
- if the handler is not lazy loaded and the handler is of string type. At this point the handler as a BeanName, in the Spring container to get the bean object of the handler.
- the urlPath is verified, if a urlPath corresponds to more than one different handler, the code will throw an exception.
- the special urlPath is handled separately, the
setRootHandler
method andsetDefaultHandler
method are called for “/”, “/*” respectively for special handling. - record the correspondence between url and handler in handlerMap. The code
this.handlerMap.put(urlPath, resolvedHandler)
stores the url and handler into the hash hash by key-value pairs.
Handler lookup
The AbstractUrlHandlerMapping
class specifies how to get the corresponding handler from a url.
The AbstractUrlHandlerMapping
class overrides the getHandlerInternal method. The logic to get the handler from the url is written in the getHandlerInternal
method.
|
|
In the getHandlerInternal
method, the program will first get a url based on the request, and then use the lookupHandler method to get the corresponding Handler.
lookupHandler method
The lookupHandler
method is a method to find the corresponding Handler by url. lookupHandler is firstly retrieved directly from the HandlerMap. If the Handler is found, it will be returned directly.
If you can’t get it directly from the handlerMap, you will use the PathPattern to match the pattern. If a url matches more than one PathPattern, the PathPattern will be sorted and the best one will be taken.
If the Handler is of type String, then the Handler is the name of the Handle bean. Then find the corresponding bean in the Spring container based on this BeanName.
After getting the Handler, the Handler is validated using validateHandler
. validateHandler is a template method, which is mainly left to subclasses to extend the implementation.
Finally, the buildPathExposingHandler
method is used to add some interceptors to this Handler.
buildPathExposingHandler
The buildPathExposingHandler
method mainly registers two internal interceptors to the Handler. They are the PathExposingHandlerInterceptor
and the UriTemplateVariablesHandlerInterceptor
interceptor.
AbstractDetectingUrlHandlerMapping
In AbstractDetectingUrlHandlerMapping
class, the main thing is to override the initApplicationContext()
method of the parent class. In the initApplicationContext()
method, the detectHandlers()
method is called.
|
|
In the method detectHandlers()
is called, the following steps are done.
- Get the names of all beans in the Spring container.
- loop through all the bean names and call the determineUrlsForHandler method for each beanName to get the url corresponding to that beanName.
- then call the registerHandler(urls, beanName) method of the parent class to register the url and the handler.
The determineUrlsForHandler(beanName)
method in the AbstractDetectingUrlHandlerMapping
class is just an abstract method, which is left to the subclasses for concrete implementation.
BeanNameUrlHandlerMapping
The Spring MVC container initializes the BeanNameUrlHandlerMapping
component when it initializes the components of the HandlerMapping
type by default when it initializes the components of the AbstractUrlHandlerMapping
series.
The BeanNameUrlHandlerMapping
class inherits from the parent class AbstractDetectingUrlHandlerMapping
, and the child class mainly overrides the determineUrlsForHandler method. determineUrlsForHandler method Finally, the name of the bean and the corresponding bean object will be registered to the handlerMap HashMap object.
SimpleUrlHandlerMapping
SimpleUrlHandlerMapping
class inherits from the parent class AbstractUrlHandlerMapping
, which has a Map<String, Object>
type urlMap property. SimpleUrlHandlerMapping
class will iterate through the urlMap in the registerHandlers(Map<String, Object> urlMap)
method and then call AbstractUrlHandlerMapping
parent class registerHandler(String urlPath, Object handler)
method to register the url and HandlerMapping
.
In addition to the urlMap property of type Map<String, Object>
. the SimpleUrlHandlerMapping
class also provides the use of Properties for url registration. With the setMappings(Properties mappings)
method, SimpleUrlHandlerMapping
will merge the mappings into the urlMap property. Then the registration logic of urlMap properties is carried out.