Backend Development 12 min read

How Spring’s DispatcherServlet Handles Requests: A Deep Dive into the Dispatch Process

This article explains how Spring’s DispatcherServlet processes incoming HTTP requests by locating the appropriate HandlerMapping, selecting a HandlerAdapter, invoking pre‑ and post‑handle interceptors, executing the controller method, and finally rendering the response or handling errors, with detailed code examples.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
How Spring’s DispatcherServlet Handles Requests: A Deep Dive into the Dispatch Process

Environment

Spring 5.3.24

1 Request Entry

<code>public class DispatcherServlet extends FrameworkServlet {
   protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
     HandlerExecutionChain mappedHandler = null;
     try {
       ModelAndView mv = null;
       Exception dispatchException = null;
       try {
         // 2.1 Obtain the handler chain via HandlerMapping (Controller + Interceptors)
         mappedHandler = getHandler(processedRequest);
         if (mappedHandler == null) {
           noHandlerFound(processedRequest, response);
           return;
         }
         // 2.2 Find a suitable HandlerAdapter for the HandlerMethod
         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
         // 2.3 Execute preHandle of interceptors; abort if false
         if (!mappedHandler.applyPreHandle(processedRequest, response)) {
           return;
         }
         // 2.4 Actually invoke the handler
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
         // 2.5 Execute postHandle of interceptors
         mappedHandler.applyPostHandle(processedRequest, response, mv);
       } catch (Exception ex) {
         dispatchException = ex;
       } catch (Throwable err) {
         dispatchException = new NestedServletException("Handler dispatch failed", err);
       }
       // 2.6 Process the result, handling exceptions and rendering
       processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
     }
     // ...
   }
 }</code>

2 Process Request

2.1 Get Request Handling Chain

This step uses HandlerMapping to obtain a HandlerExecutionChain that contains the controller (HandlerMethod) and any interceptors.

<code>public class DispatcherServlet {
   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>

Example: RequestMappingHandlerMapping implements this logic.

<code>public abstract class AbstractHandlerMapping {
   public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
     Object handler = getHandlerInternal(request);
     HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
     return executionChain;
   }
   protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
     HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
         (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
     for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
       if (interceptor instanceof MappedInterceptor) {
         MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
         if (mappedInterceptor.matches(request)) {
           chain.addInterceptor(mappedInterceptor.getInterceptor());
         }
       } else {
         chain.addInterceptor(interceptor);
       }
     }
     return chain;
   }
 }</code>

2.2 Get HandlerAdapter

After obtaining the HandlerMethod from the previous step, Spring looks for a matching HandlerAdapter (typically RequestMappingHandlerAdapter ).

<code>public class DispatcherServlet {
   protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
     if (this.handlerAdapters != null) {
       for (HandlerAdapter adapter : this.handlerAdapters) {
         if (adapter.supports(handler)) {
           return adapter;
         }
       }
     }
     throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
   }
 }</code>

RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter , which always returns true for supports .

<code>public abstract class AbstractHandlerMethodAdapter {
   public final boolean supports(Object handler) {
     return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
   }
 }
 public class RequestMappingHandlerAdapter {
   protected boolean supportsInternal(HandlerMethod handlerMethod) {
     return true;
   }
 }</code>

2.3 Execute Interceptor preHandle

<code>public class HandlerExecutionChain {
   boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
     for (int i = 0; i < this.interceptorList.size(); i++) {
       HandlerInterceptor interceptor = this.interceptorList.get(i);
       if (!interceptor.preHandle(request, response, this.handler)) {
         triggerAfterCompletion(request, response, null);
         return false;
       }
       this.interceptorIndex = i;
     }
     return true;
   }
 }</code>

2.4 Actual Request Handling

<code>public class DispatcherServlet {
   protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
     mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
   }
 }</code>

The AbstractHandlerMethodAdapter delegates to the concrete adapter’s handleInternal method.

<code>public abstract class AbstractHandlerMethodAdapter {
   public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
     return handleInternal(request, response, (HandlerMethod) handler);
   }
 }
 public class RequestMappingHandlerAdapter {
   protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
     ModelAndView mav;
     if (this.synchronizeOnSession) {
       // ...
     } else {
       // Invoke the controller method
       mav = invokeHandlerMethod(request, response, handlerMethod);
     }
     return mav;
   }
   protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
     ServletWebRequest webRequest = new ServletWebRequest(request, response);
     try {
       WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
       ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
       ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
       if (this.argumentResolvers != null) {
         invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
       }
       if (this.returnValueHandlers != null) {
         invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
       }
       invocableMethod.setDataBinderFactory(binderFactory);
       invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
       ModelAndViewContainer mavContainer = new ModelAndViewContainer();
       mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
       modelFactory.initModel(webRequest, mavContainer, invocableMethod);
       mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
       invocableMethod.invokeAndHandle(webRequest, mavContainer);
       if (asyncManager.isConcurrentHandlingStarted()) {
         return null;
       }
       return getModelAndView(mavContainer, modelFactory, webRequest);
     } finally {
       webRequest.requestCompleted();
     }
   }
   private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
     modelFactory.updateModel(webRequest, mavContainer);
     if (mavContainer.isRequestHandled()) {
       return null;
     }
     ModelMap model = mavContainer.getModel();
     ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
     if (!mavContainer.isViewReference()) {
       mav.setView((View) mavContainer.getView());
     }
     return mav;
   }
 }
</code>

2.5 Execute Interceptor postHandle

<code>public class HandlerExecutionChain {
   void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
     for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
       HandlerInterceptor interceptor = this.interceptorList.get(i);
       interceptor.postHandle(request, response, this.handler, mv);
     }
   }
 }</code>

2.6 Process Result

<code>public class DispatcherServlet {
   protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
     processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
   }
   private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
       @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
     boolean errorView = false;
     if (exception != null) {
       if (exception instanceof ModelAndViewDefiningException) {
         mv = ((ModelAndViewDefiningException) exception).getModelAndView();
       } else {
         Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
         mv = processHandlerException(request, response, handler, exception);
         errorView = (mv != null);
       }
     }
     if (mv != null && !mv.wasCleared()) {
       render(mv, request, response);
       if (errorView) {
         WebUtils.clearErrorRequestAttributes(request);
       }
     }
     if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
       return;
     }
     if (mappedHandler != null) {
       mappedHandler.triggerAfterCompletion(request, response, null);
     }
   }
 }</code>

End of the dispatch flow.

SpringHandlerMappingHandlerAdapterdispatcher-servlet
Spring Full-Stack Practical Cases
Written by

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.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.