How does Spring detect and parse multipart requests, and what is StandardServletMultipartResolver?
answer
- DispatcherServlet.isMultipart -> wrap request
- bean name must be 'multipartResolver'
- StandardServletMultipartResolver delegates to container getParts()
- MultipartAutoConfiguration + MultipartConfigElement
- CommonsMultipartResolver removed in Spring 6
basics
~10 sThe DispatcherServlet asks a MultipartResolver bean (named multipartResolver) whether the request is multipart; if so it wraps it as a MultipartHttpServletRequest. Spring Boot auto-configures StandardServletMultipartResolver, which delegates parsing to the Servlet container.
solid answer
~40 sOn each request, DispatcherServlet calls MultipartResolver.isMultipart(); if true it wraps the request in a MultipartHttpServletRequest so parts become MultipartFiles. Spring Boot auto-registers a bean named multipartResolver of type StandardServletMultipartResolver, which relies on the Servlet 3.0+ container's own multipart parsing (HttpServletRequest.getParts()) — no third-party library. It's configured through a MultipartConfigElement derived from spring.servlet.multipart.* properties (max sizes, temp location, file-size-threshold, resolve-lazily). The older CommonsMultipartResolver (Apache Commons FileUpload) existed for pre-Servlet-3.0 containers but was removed in Spring Framework 6. Because parsing is container-driven, size limits are enforced by the container and exceeding them raises MaxUploadSizeExceededException. You rarely define the resolver yourself; you just set properties.
code
java · 26 lines// Typical Spring Boot: no bean needed — just properties (application.yml):
// spring.servlet.multipart:
// max-file-size: 20MB
// max-request-size: 25MB
// file-size-threshold: 2KB
// location: /var/app/tmp
// resolve-lazily: false
// Only if you must customize beyond properties (bean name is mandatory):
@Configuration
public class MultipartConfig {
@Bean
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory f = new MultipartConfigFactory();
f.setMaxFileSize(DataSize.ofMegabytes(20));
f.setMaxRequestSize(DataSize.ofMegabytes(25));
f.setLocation("/var/app/tmp");
return f.createMultipartConfig();
}
@Bean(name = "multipartResolver") // name is required for DispatcherServlet lookup
public StandardServletMultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}
}go deeper
Know Spring Boot auto-configures multipart; you just set properties.
Explain the DispatcherServlet resolver lookup, StandardServletMultipartResolver delegating to the container, and the mandatory bean name.
Discuss MultipartConfigElement, container-level limits interacting with Spring's, and resolve-lazily semantics.
Reason about parsing position relative to filters/security, container portability, and when a custom resolver is justified.
## The dispatch flow 1. A request reaches **`DispatcherServlet`**. 2. `DispatcherServlet.checkMultipart(request)` calls the injected **`MultipartResolver.isMultipart(request)`** (true when `Content-Type` starts with `multipart/`). 3. If multipart, the resolver wraps the request in a **`MultipartHttpServletRequest`** (a subinterface of `HttpServletRequest`) so handler-argument resolvers can expose parts as **`MultipartFile`**. 4. After the request completes, `DispatcherServlet` calls `cleanupMultipart(...)` to release temp resources (for the standard resolver, the container manages this). ## `StandardServletMultipartResolver` - Implementation of `MultipartResolver` that delegates to the **Servlet 3.0+ container's native multipart support** — it calls `HttpServletRequest.getParts()` / `getPart(name)`. No Apache Commons dependency. - Requires the servlet to have multipart config (a `MultipartConfigElement`, equivalent to `@MultipartConfig`). Spring Boot wires this automatically from `MultipartProperties`. - **Bean name matters**: `DispatcherServlet` looks up the resolver by the fixed bean name **`multipartResolver`**. A custom resolver must use that name to be picked up. ## Spring Boot auto-configuration `MultipartAutoConfiguration` (active when `spring.servlet.multipart.enabled=true`, the default) registers: - a `MultipartConfigElement` built from `spring.servlet.multipart.*`, and - a `StandardServletMultipartResolver` bean named `multipartResolver`. So in a typical Boot app you configure behavior purely via properties; you don't declare beans. ### Key properties (`spring.servlet.multipart.*`) - `enabled` (default `true`) — turn multipart handling on/off. - `max-file-size` (default `1MB`) — per-file cap. - `max-request-size` (default `10MB`) — whole-request cap. - `file-size-threshold` (default `0B`) — above this, the container spools the part to disk; `0` means always to disk. - `location` — temp directory for spooled files (defaults to the container temp dir). - `resolve-lazily` (default `false`) — when `true`, parsing is deferred until a part is first accessed instead of eagerly at request time. ## Legacy: `CommonsMultipartResolver` - Based on **Apache Commons FileUpload**; historically used to support **pre-Servlet-3.0** containers or to override parsing behavior. - **Removed in Spring Framework 6 (Spring Boot 3+).** On modern stacks, `StandardServletMultipartResolver` is the only built-in option. ## Gotchas - If you register a custom `MultipartResolver` bean but name it anything other than `multipartResolver`, `DispatcherServlet` won't use it. - With `StandardServletMultipartResolver`, the **container** enforces limits, so container-specific settings (e.g., Tomcat `maxSwallowSize`, `maxPostSize`) can also affect uploads independently of Spring properties. - `resolve-lazily=false` (default) means the whole multipart body is parsed before your handler runs; a payload exceeding limits fails early with `MaxUploadSizeExceededException`. - Multipart parsing happens **before** most filters that read the body; frameworks like Spring Security must see the multipart request correctly (usually fine, but body-reading filters can consume the stream). ## When to touch it Almost never define the resolver manually. Tune sizes/temp location via properties; only drop to a custom `MultipartConfigElement`/bean for unusual container or parsing needs.
- You defined a MultipartResolver bean but uploads still fail — what's a likely cause?DispatcherServlet resolves the resolver by the fixed bean name 'multipartResolver'. If your bean has a different name, it's ignored and the auto-configured (or no) resolver is used. Rename the bean or rely on Boot's auto-config.
- What replaced CommonsMultipartResolver and why?StandardServletMultipartResolver, which uses the Servlet 3.0+ container's native multipart parsing. Commons FileUpload-based CommonsMultipartResolver was removed in Spring Framework 6 since modern containers all support multipart natively.
saying these in an interview costs you the question
- Saying you must always add Apache Commons FileUpload for uploads (not on Servlet 3.0+/Spring 6).
- Registering a resolver bean under a non-'multipartResolver' name and expecting it to work.
- Claiming Spring parses multipart itself rather than delegating to the container (for the standard resolver).
- Thinking multipart handling is off by default (it's enabled).