Understanding Spring MVC’s internal request processing can transform how you architect controllers, filters, interceptors, and exception handling in your application. Let’s walk through the typical execution flow—complete with illustrations from real-world projects.
🧭 1. DispatcherServlet: Spring’s Front Controller
Every HTTP request enters your Spring MVC app via the DispatcherServlet. Acting as the Front Controller, it:
- Receives the client’s request.
- Dispatches it downstream through configured filters, handlers, resolvers, and ultimately, into your controllers.
All routing and processing logic starts here.
🧩 2. HandlerMapping: Finding the Right Controller
Next, HandlerMapping works to map the request’s URL (or annotations like @RequestMapping
) to a specific controller or handler method. If no match is found, a 404 is returned.
⚙️ 3. HandlerAdapter: Invoking Your Controller
Once the handler is identified, HandlerAdapter—typically RequestMappingHandlerAdapter
—takes over. It:
- Resolves method arguments (via
@RequestParam
,@PathVariable
,@RequestBody
, etc.). - Handles message conversion for JSON, XML, or form data.
- Calls your controller method with the populated parameters.
🌿 4. Controller Execution and Response Preparation
Your controller processes business logic, populates a Model
, and returns either:
- A view name (for HTML responses), or
- A value object (for JSON/XML) using
@ResponseBody
orHttpEntity
.
🔄 5a. ViewResolver: Rendering HTML
If a view name is returned (e.g., return "dashboard";
), ViewResolver locates the appropriate view (Thymeleaf, JSP, etc.), and renders it using the model data.
🔄 5b. HttpMessageConverter: Returning JSON/XML
For REST APIs or @ResponseBody
endpoints, HttpMessageConverter serializes the return object into JSON/XML based on headers and return types. The converter uses the Accept
and Content-Type
headers, along with ReturnValueHandler
, to generate the correct response.
🚪 6. Response Returned to Client
Finally, the view or serialized body travels back through any response filters and is sent as the HTTP response.
🔍 Why This Flow Matters
- Cross-cutting concerns (like logging, CORS, auth) should be handled in filters or interceptors early in the flow.
- Custom argument resolvers or message converters can be plugged into the HandlerAdapter to support extra formats.
- Global exception handling is implemented via
@ControllerAdvice
, catching issues during controller execution or rendering. - Optimizing filters, interceptors, and message converters directly improves the efficiency of the entire pipeline.
🛠 Real-World Example: Performance Debugging
In one SaaS project, slow API responses stemmed from initializing heavy @ModelAttribute
objects too early. By inspecting the flow:
- I saw that argument resolution occurred before controller logic.
- Optimizing that part dramatically improved performance—reducing average response time by over 30%.
✅ Key Takeaways
- DispatcherServlet is the gateway for every request.
- HandlerMapping → HandlerAdapter → Controller → ViewResolver/MessageConverter → Response is the canonical flow.
- Awareness of each step helps you build cleaner, more efficient, and maintainable web applications.