How Spring MVC Processes a Request: From DispatcherServlet to ViewResolver
This article explains step‑by‑step how Spring MVC handles an incoming HTTP request, detailing the roles of DispatcherServlet, HandlerMapping, HandlerAdapter, argument and return value resolvers, and ViewResolver, and includes key code excerpts that illustrate the matching and initialization processes.
Overview
When a request arrives, Spring processes it through a series of core components.
Spring MVC Processing Flow
DispatcherServlet – entry point for all requests.
HandlerMapping – maps request URLs to handlers.
HandlerAdapter – invokes the matched handler.
HandlerMethodArgumentResolver – resolves method arguments.
HandlerMethodReturnValueHandler – processes the return value.
ViewResolver – resolves views when a ModelAndView is returned.
Getting HandlerMapping
The servlet retrieves all HandlerMapping beans from the application context.
<code>public class DispatcherServlet extends FrameworkServlet {
private List<HandlerMapping> handlerMappings;
private void initHandlerMappings(ApplicationContext context) {
// Find all HandlerMapping beans, including ancestors.
Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
this.handlerMappings = new ArrayList<>(matchingBeans.values());
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
}
</code>Finding the Appropriate HandlerMapping
The servlet iterates over the retrieved HandlerMapping instances to locate one that matches the current request URI.
<code>public class DispatcherServlet extends FrameworkServlet {
private List<HandlerMapping> handlerMappings;
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerExecutionChain mappedHandler = null;
// Find a HandlerMapping that can handle the request.
mappedHandler = getHandler(processedRequest);
}
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;
}
}
</code>Spring provides five default HandlerMapping implementations, with RequestMappingHandlerMapping being the most commonly used.
HandlerMapping Matching Logic
The matching process delegates to
AbstractHandlerMapping#getHandler, which calls the subclass‑specific
getHandlerInternalmethod.
<code>public abstract class AbstractHandlerMapping {
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
// ...
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
// ...
return executionChain;
}
}
public abstract class AbstractHandlerMethodMapping {
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = initLookupPath(request);
try {
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
} catch (Exception e) {
// ...
}
}
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.getHandlerMethod();
}
// ...
return null;
}
}
</code>Initializing HandlerMethods
After a matching HandlerMapping is found, Spring initializes all
@RequestMappingmethods.
<code>public class RequestMappingHandlerMapping {
public void afterPropertiesSet() {
super.afterPropertiesSet();
}
}
public abstract class AbstractHandlerMethodMapping {
public void afterPropertiesSet() {
initHandlerMethods();
}
protected void initHandlerMethods() {
for (String beanName : getCandidateBeanNames()) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
processCandidateBean(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
protected void processCandidateBean(String beanName) {
Class<?> beanType = null;
try {
beanType = obtainApplicationContext().getType(beanName);
} catch (Exception e) {
// ...
}
if (beanType != null && isHandler(beanType)) {
detectHandlerMethods(beanName);
}
}
protected void detectCandidateMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass());
if (handlerType != null) {
Class<?> userType = ClassUtils.getUserClass(handlerType);
Map<Method, T> methods = MethodIntrospector.selectMethods(userType, method -> {
try {
return getMappingForMethod(method, userType);
} catch (Exception e) {
// ...
}
});
methods.forEach((method, mapping) -> {
Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
registerHandlerMethod(handler, invocableMethod, mapping);
});
}
}
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
class MappingRegistry {
public void register(T mapping, Object handler, Method method) {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
for (String path : directPaths) {
this.pathLookup.add(path, mapping);
}
}
}
}
</code>That concludes the request handling flow in Spring MVC.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.