How does Spring MVC decide what value to pass to each parameter of a @RequestMapping controller method?
answer
- supportsParameter -> resolveArgument
- first match wins in a composite
- RequestMappingHandlerAdapter holds the lists
- ModelAndViewContainer carries model + view
- return side = HandlerMethodReturnValueHandler
basics
~20 sFor every controller-method parameter Spring asks a list of HandlerMethodArgumentResolver strategies which one can handle it. The first that says yes resolves the value (from a request param, path variable, body, etc.) and passes it in.
solid answer
~30 sSpring MVC controller methods have flexible signatures because RequestMappingHandlerAdapter holds an ordered list of HandlerMethodArgumentResolver strategies (a composite). For each MethodParameter it calls supportsParameter until one returns true, then that resolver's resolveArgument produces the value. Built-ins cover @RequestParam, @PathVariable, @RequestHeader, @RequestBody, @ModelAttribute, Model/Map, HttpServletRequest, Principal, RedirectAttributes, and more. Symmetrically, HandlerMethodReturnValueHandler strategies process the return value (view name, @ResponseBody, ModelAndView, etc.). This strategy-based design is why you can add or reorder parameters freely and why the framework is extensible: you can plug in your own resolver/handler without changing controller code.
code
java · 16 lines// The two strategy interfaces Spring MVC iterates for every handler method.
public interface HandlerMethodArgumentResolver {
boolean supportsParameter(MethodParameter parameter);
Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception;
}
public interface HandlerMethodReturnValueHandler {
boolean supportsReturnType(MethodParameter returnType);
void handleReturnValue(Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception;
}go deeper
Know the two interfaces exist and that Spring picks the first resolver that supports a parameter.
Explain the composite, first-match ordering, ModelAndViewContainer, and name several built-in resolvers.
Discuss RequestMappingHandlerAdapter wiring, catch-all ordering, and dual-SPI processors like RequestResponseBodyMethodProcessor.
Reason about extensibility, resolver caching, and how this SPI keeps controller signatures decoupled from transport concerns.
### The problem this solves A Spring MVC controller method can declare almost any parameter list — `@RequestParam String q`, `@PathVariable Long id`, `@RequestBody Order body`, `Model model`, `HttpServletRequest req`, `Principal user`, `RedirectAttributes ra`. Something has to look at each parameter, figure out where its value comes from, and produce it before the method is invoked. That something is the **argument-resolver** subsystem. ### The core SPI Spring defines two strategy interfaces (SPIs = Service Provider Interfaces, i.e. extension points): - **`HandlerMethodArgumentResolver`** — resolves an incoming parameter value: - `boolean supportsParameter(MethodParameter parameter)` — can I handle this parameter? - `Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory)` — produce the value. - **`HandlerMethodReturnValueHandler`** — processes what the method returns: - `boolean supportsReturnType(MethodParameter returnType)` - `void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest)` `MethodParameter` is Spring's reflection wrapper that carries the parameter's type, index, annotations, and generic info. ### Where they live and how they run `RequestMappingHandlerAdapter` (the adapter that actually invokes `@RequestMapping` methods) builds two composites at startup: a `HandlerMethodArgumentResolverComposite` and a `HandlerMethodReturnValueHandlerComposite`. Each composite holds an **ordered list**. When a request arrives: 1. For each method parameter, the composite iterates its resolvers, calling `supportsParameter`; the **first** that returns `true` wins and its `resolveArgument` runs (results are cached per parameter for speed). 2. The method is invoked with the resolved args. 3. The return value is handed to the return-value composite, which finds the first handler whose `supportsReturnType` is true and calls `handleReturnValue`. ### The shared context object Both sides get a **`ModelAndViewContainer`** — a mutable bag that carries the model attributes and the chosen view (or a `@ResponseBody`-was-handled flag) across resolution and handling. For example the `Model` argument resolver hands the controller the container's model; a view-name return handler sets the view on the same container. ### Representative built-in resolvers - `RequestParamMethodArgumentResolver` — `@RequestParam`, and (in catch-all mode) simple types. - `PathVariableMethodArgumentResolver` — `@PathVariable`. - `RequestHeaderMethodArgumentResolver` — `@RequestHeader`. - `RequestResponseBodyMethodProcessor` — `@RequestBody` / `@ResponseBody` (implements BOTH SPIs; delegates to `HttpMessageConverter`s). - `ServletModelAttributeMethodProcessor` — `@ModelAttribute` and, in catch-all mode, complex objects (data binding). - `ModelMethodProcessor` / `MapMethodProcessor` — `Model`, `ModelMap`, `Map` parameters. - `RedirectAttributesMethodArgumentResolver` — `RedirectAttributes`. - `ServletRequestMethodArgumentResolver` — `HttpServletRequest`, `HttpSession`, `Principal`, `Locale`, etc. ### Gotchas / edge cases - **First-match wins**: order matters. The last two default resolvers are *catch-alls* (simple types → request param; everything else → model attribute), so an unannotated `String` becomes a request param and an unannotated object gets data-bound. - Some processors implement **both** SPIs (`RequestResponseBodyMethodProcessor`, `ModelAttributeMethodProcessor`), so the same class appears in both composites. - Resolution happens **before** the method runs; a resolver can throw (e.g. `MissingServletRequestParameterException`) and short-circuit into exception handling. ### When to care Day to day you rely on built-ins. You reach for this knowledge when you need a **custom parameter** (e.g. inject the current tenant or a decoded principal object) or a **custom return type** — then you implement the SPI and register it.
- If a controller parameter has no annotation and is a simple type like String, how is it resolved?By the catch-all RequestParamMethodArgumentResolver (configured with useDefaultResolution=true), which is placed last, so an unannotated simple type is treated as a @RequestParam by its name.
- What object lets the argument side and the return side communicate?ModelAndViewContainer — it carries the model attributes and the selected view/redirect state across resolvers, the handler invocation, and return-value handlers.
saying these in an interview costs you the question
- Thinking Spring uses reflection parameter names alone with no strategy layer
- Believing all resolvers run for every parameter (only the first supporting one runs)
- Confusing HandlerMethodArgumentResolver with HandlerInterceptor or Filter