skip to content

What does initStrategies() do, and how does DispatcherServlet discover its special beans at startup?

level: seniorimportance: should knowfreq 55%

answer

  1. onRefresh → initStrategies (nine initXxx)
  2. detect-all by type + @Order for Mappings/Adapters/Resolvers
  3. single ones by fixed bean name
  4. fallback = DispatcherServlet.properties
  5. cached at startup, not per request

basics

~10 s

On context refresh, initStrategies() populates DispatcherServlet's strategy beans (HandlerMappings, HandlerAdapters, ViewResolvers, resolvers, etc.) by looking them up from the WebApplicationContext, falling back to defaults in DispatcherServlet.properties if none are defined.

solid answer

~30 s

When the WebApplicationContext is refreshed, DispatcherServlet's `onRefresh` calls `initStrategies(context)`, which runs a series of `initXxx` methods: `initMultipartResolver`, `initLocaleResolver`, `initThemeResolver`, `initHandlerMappings`, `initHandlerAdapters`, `initHandlerExceptionResolvers`, `initRequestToViewNameTranslator`, `initViewResolvers`, `initFlashMapManager`. For the multi-instance ones (HandlerMappings, HandlerAdapters, ExceptionResolvers, ViewResolvers) it uses `detectAllHandlerMappings` (default true) to pull **all** matching beans from the context by type and sort them with `@Order`/`Ordered`. For single ones (LocaleResolver, MultipartResolver, ThemeResolver, FlashMapManager) it looks up a bean by a **well-known name**. If nothing is found, it falls back to defaults declared in `DispatcherServlet.properties`. These strategy lists are cached as fields, so lookup is one-time at startup, not per request.

code

java · 24 lines
java
// DispatcherServlet (abridged) — how the strategies get wired
protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
}

protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);
    initLocaleResolver(context);
    initThemeResolver(context);
    initHandlerMappings(context);        // detect-all + order
    initHandlerAdapters(context);
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);          // detect-all + order
    initFlashMapManager(context);
}

// Just declaring a bean of the right type makes it detected:
@Bean
public HandlerMapping myCustomMapping() {
    SimpleUrlHandlerMapping m = new SimpleUrlHandlerMapping();
    m.setOrder(0); // ordered ahead of others
    return m;
}

go deeper

for a junior

Know DispatcherServlet gets its helper beans from the Spring context at startup.

for a middle

Know initStrategies runs on refresh and populates the strategy beans, with defaults available.

for a senior

Explain detect-all-by-type + ordering vs by-name, and the DispatcherServlet.properties fallback.

for a principal

Reason about ordering/shadowing risks, ancestor-context visibility, and why detection is cached and refresh-bound.

## Where it fits `DispatcherServlet` extends `FrameworkServlet`, which extends `HttpServletBean`. Servlet init (`init()`) leads to `FrameworkServlet.initServletBean()` → creates/refreshes the **WebApplicationContext** → fires `onRefresh(context)`. `DispatcherServlet.onRefresh` simply calls **`initStrategies(context)`**. So strategy bootstrapping is tied to **context refresh**, and re-runs if the context is refreshed again. ## The initXxx methods `initStrategies` calls, in order: 1. `initMultipartResolver` — by name `multipartResolver` (single, optional; no default → multipart disabled if absent... in Boot it's autoconfigured). 2. `initLocaleResolver` — by name `localeResolver`, default `AcceptHeaderLocaleResolver`. 3. `initThemeResolver` — by name `themeResolver` (themes deprecated in newer versions). 4. `initHandlerMappings` — **all** beans of type `HandlerMapping` when `detectAllHandlerMappings` is true (the default); otherwise a single bean named `handlerMapping`. Sorted via `AnnotationAwareOrderComparator` (respects `@Order`/`Ordered`). 5. `initHandlerAdapters` — same detect-all + order logic for `HandlerAdapter`. 6. `initHandlerExceptionResolvers` — same for `HandlerExceptionResolver`. 7. `initRequestToViewNameTranslator` — by name, default `DefaultRequestToViewNameTranslator`. 8. `initViewResolvers` — detect-all for `ViewResolver`, ordered. 9. `initFlashMapManager` — by name, default `SessionFlashMapManager`. ## detect-all vs. by-name - **Multi-strategy** beans (Mappings, Adapters, ExceptionResolvers, ViewResolvers) are collected by **type** (`BeanFactoryUtils.beansOfTypeIncludingAncestors`), so ancestor (root) contexts are included, and the results are ordered. - **Single-strategy** beans (Locale/Theme/Multipart resolver, FlashMapManager) are looked up by a **fixed bean name** — get the name wrong and Spring won't detect it. ## The defaults fallback: DispatcherServlet.properties If a strategy yields nothing from the context, DispatcherServlet reads defaults from `DispatcherServlet.properties` (packaged next to the class). This is why a bare Spring MVC app still has a working `BeanNameUrlHandlerMapping`, `RequestMappingHandlerMapping`, etc. In practice, `@EnableWebMvc` / Spring Boot's MVC auto-config register the modern strategies as beans, so the properties fallback rarely kicks in. ## Caching / performance Each strategy list is stored in a DispatcherServlet field (`handlerMappings`, `handlerAdapters`, …). Detection happens **once** at init; per request, `getHandler` just iterates the cached list. So adding a HandlerMapping bean after refresh won't be seen without a re-refresh. ## Gotchas - **`detectAllHandlerMappings=false`** (rare) switches to single-bean-by-name mode and will silently ignore all but the one named `handlerMapping`. - Beans in the **root** context are visible to the servlet context because detection includes ancestors — but you normally declare web strategies in the servlet (child) context. - Ordering matters: HandlerMappings are consulted in order, first match wins; a mis-ordered custom mapping can shadow `RequestMappingHandlerMapping`. - Strategy discovery is **type/name based**, not annotation based — a `@Bean` of the right type is enough; you don't annotate it specially.

  • If you define zero HandlerMapping beans, does Spring MVC still route requests?
    Yes — DispatcherServlet falls back to defaults in DispatcherServlet.properties. Though with @EnableWebMvc/Boot, the modern mappings are already registered as beans.
  • Why are HandlerMappings detected by type but MultipartResolver by name?
    Multi-instance strategies are meant to be composed and ordered, so they're collected by type. Single-instance strategies use a fixed conventional bean name so a stray extra bean of that type doesn't create ambiguity.
  • When does initStrategies run — once per request or once at startup?
    Once, on WebApplicationContext refresh (via onRefresh). Results are cached in fields; per-request code just iterates the cached lists.

saying these in an interview costs you the question

  • Saying strategies are looked up per request (they're cached at startup)
  • Thinking you must annotate strategy beans specially rather than just declare the right type/name
  • Claiming all strategies are found by bean name
  • Believing removing @EnableWebMvc leaves no handler mappings at all (defaults still apply)

context