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

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);
     }
     // ...
   }
 }

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.

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;
   }
 }

Example: RequestMappingHandlerMapping implements this logic.

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;
   }
 }

2.2 Get HandlerAdapter

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

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");
   }
 }
RequestMappingHandlerAdapter

extends AbstractHandlerMethodAdapter, which always returns true for supports.

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;
   }
 }

2.3 Execute Interceptor preHandle

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;
   }
 }

2.4 Actual Request Handling

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

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

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;
   }
 }

2.5 Execute Interceptor postHandle

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);
     }
   }
 }

2.6 Process Result

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);
     }
   }
 }

End of the dispatch flow.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

HandlerMappingHandlerAdapterdispatcher-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

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.