Issue
Iam curious about internal working of Spring request mapping . Does having a requestmapping annotation at class level speed up resolving controllers for a request ?
How @RequestMapping internally works in Spring Boot? - read this answer and similar ones.Are controllers and urls mapped during initial startup and stored in a registry ?Because I Found these log traces while starting a spring boot application .
LogTrace : s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/employeedetails/{name}/{id} || /employeedetails],methods=[GET],produces=[application/json]}" onto public java.util.HashMap com.example.controller.EmployeeController.getEmployees(java.util.Optional,java.lang.String) throws java.lang.InterruptedException 2019-06-01 13:32:48.289 INFO 60719 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
Are controllers+methods and urls are mapped initially during startup or they are iterated everytime for a request? I wanted to know whether having a class level request annotation makes any difference during request mapping to controller.
Solution
Are controllers+methods and urls are mapped initially during startup or they are iterated everytime for a request?
With default HandlerMapping
implementation, Url mappings of Spring controllers are done at startup. That would make no sense to do that at each request invocation since the url mapping cannot change once the container was started.
Beyond this question, consider Controllers as beans and these are set/initialized by Spring a single time : at container startup.
So consider the class level annotation for @RequestMapping
simply as a shortcut to be dry.
Here is a code that should interest you : AbstractUrlHandlerMapping.getHandlerInternal()
used under the hood by the default implementation of HandlerMapping
:
@Override
@Nullable
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
Object handler = lookupHandler(lookupPath, request);
if (handler == null) {
// We need to care for the default handler directly, since we need to
// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
Object rawHandler = null;
if ("/".equals(lookupPath)) {
rawHandler = getRootHandler();
}
if (rawHandler == null) {
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
// Bean name or resolved handler?
if (rawHandler instanceof String) {
String handlerName = (String) rawHandler;
rawHandler = obtainApplicationContext().getBean(handlerName);
}
validateHandler(rawHandler, request);
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
}
if (handler != null && logger.isDebugEnabled()) {
logger.debug("Mapping [" + lookupPath + "] to " + handler);
}
else if (handler == null && logger.isTraceEnabled()) {
logger.trace("No handler mapping found for [" + lookupPath + "]");
}
return handler;
}
The interesting part is that the handler is created a single time in the whole life of the bean :
if (handler == null) {
// init handler...
}
return handler;
Note that the HandlerMapping
interface that defines getHandler()
specifies that you could create your own logic for the mapping resolution :
Interface to be implemented by objects that define a mapping between requests and handler objects. This class can be implemented by application developers, although this is not necessary, as BeanNameUrlHandlerMapping and RequestMappingHandlerMapping are included in the framework. The former is the default if no HandlerMapping bean is registered in the application context. HandlerMapping implementations can support mapped interceptors but do not have to.
So not caching url mappings is fairly possible by creating your own implementation of handler mapping , but that is of course not the behavior of the default implementation for fair reasons.
Answered By - davidxxx