Mastering Spring MVC Auto-Configuration in Spring Boot 2.6.14
Explore how Spring Boot 2.6.14 automatically configures Spring MVC, including view resolvers, static resources, converters, message converters, JSON serialization, content negotiation, and error handling, and learn how to customize these features with WebMvcConfigurer, WebMvcRegistrations, and related beans for full control.
Spring MVC Auto-Configuration
Spring Boot 2.6.14 automatically configures Spring MVC, adding beans such as ContentNegotiatingViewResolver, BeanNameViewResolver, static resource support, Converter, GenericConverter, Formatter, HttpMessageConverters, MessageCodesResolver, static index.html handling, and ConfigurableWebBindingInitializer.
To keep these defaults while adding custom MVC components (interceptors, formatters, view controllers, etc.), implement a @Configuration class that implements WebMvcConfigurer, without using @EnableWebMvc.
For custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver while preserving Boot's auto‑configuration, declare a bean of type WebMvcRegistrations:
<code>public interface WebMvcRegistrations {
default RequestMappingHandlerMapping getRequestMappingHandlerMapping() { return null; }
default RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() { return null; }
default ExceptionHandlerExceptionResolver getExceptionHandlerExceptionResolver() { return null; }
}
</code>Spring Boot uses EnableWebMvcConfiguration internally to apply a custom WebMvcRegistrations bean if present:
<code>public static class EnableWebMvcConfiguration {
private final WebMvcRegistrations mvcRegistrations;
public EnableWebMvcConfiguration(ObjectProvider<WebMvcRegistrations> mvcRegistrationsProvider) {
this.mvcRegistrations = mvcRegistrationsProvider.getIfUnique();
}
@Override
protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
if (this.mvcRegistrations != null) {
RequestMappingHandlerAdapter adapter = this.mvcRegistrations.getRequestMappingHandlerAdapter();
if (adapter != null) {
return adapter;
}
}
return super.createRequestMappingHandlerAdapter();
}
}
</code>Message Conversion (HttpMessageConverters)
Spring MVC uses HttpMessageConverter to convert HTTP requests and responses. Default converters handle JSON (Jackson), XML (Jackson XML or JAXB), and strings (UTF‑8). Custom converters can be added via HttpMessageConverters bean:
<code>@Configuration(proxyBeanMethods = false)
public class CustomHttpMessageConvertersConfiguration {
@Bean
public HttpMessageConverters customConverters() {
HttpMessageConverter<?> additional = new AdditionalHttpMessageConverter();
HttpMessageConverter<?> another = new AnotherHttpMessageConverter();
return new HttpMessageConverters(additional, another);
}
}
</code>Alternatively, simply register custom HttpMessageConverter beans; Spring Boot will collect them automatically:
<code>public class HttpMessageConvertersAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) {
return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList()));
}
}
</code>Custom JSON Serialization and Deserialization
When using Jackson, you can create custom JsonSerializer and JsonDeserializer classes and register them with @JsonComponent, which is meta‑annotated with @Component:
<code>@JsonComponent
public class MyJsonComponent {
public static class Serializer extends JsonSerializer<MyObject> {
@Override
public void serialize(MyObject value, JsonGenerator jgen, SerializerProvider serializers) throws IOException {
jgen.writeStartObject();
jgen.writeStringField("name", value.getName());
jgen.writeNumberField("age", value.getAge());
jgen.writeEndObject();
}
}
public static class Deserializer extends JsonDeserializer<MyObject> {
@Override
public MyObject deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException, JsonProcessingException {
ObjectCodec codec = jsonParser.getCodec();
JsonNode tree = codec.readTree(jsonParser);
String name = tree.get("name").textValue();
int age = tree.get("age").intValue();
return new MyObject(name, age);
}
}
}
</code>MessageCodesResolver
Spring MVC uses MessageCodesResolver to generate error codes from binding errors. Setting spring.mvc.message-codes-resolver-format to PREFIX_ERROR_CODE or POSTFIX_ERROR_CODE lets Spring Boot create the appropriate bean.
Static Content
By default Spring Boot serves static resources from classpath locations /static , /public , /resources , or /META-INF/resources using ResourceHttpRequestHandler. The static‑path pattern can be customized, e.g.:
<code>spring:
mvc:
static-path-pattern: "/resources/**"
</code>WebJars are served from /webjars/** . Content‑based versioning and cache busting can be enabled:
<code>spring:
web:
resources:
chain:
strategy:
content:
enabled: true
paths: "/**"
</code>Path Matching and Content Negotiation
Spring MVC matches requests to handler methods based on path patterns. Suffix pattern matching is disabled by default; you can enable it with:
<code>spring:
mvc:
contentnegotiation:
favor-path-extension: true
pathmatch:
use-suffix-pattern: true
</code>Parameter‑based content negotiation can be turned on:
<code>spring:
mvc:
contentnegotiation:
favor-parameter: true
parameter-name: "myparam"
</code>Custom media types can be added, for example:
<code>spring:
mvc:
contentnegotiation:
media-types:
markdown: "text/markdown"
</code>ConfigurableWebBindingInitializer
If a bean of type ConfigurableWebBindingInitializer is defined, Spring Boot will configure Spring MVC to use it for initializing WebDataBinder instances.
Error Handling
Spring Boot provides a default /error mapping that returns JSON for API clients and an HTML view for browsers. You can customize the response by defining an ErrorController, an ErrorAttributes bean, or a @ControllerAdvice with @ExceptionHandler methods, as shown:
<code>@ControllerAdvice(basePackageClasses = SomeController.class)
public class MyControllerAdvice extends ResponseEntityExceptionHandler {
@ResponseBody
@ExceptionHandler(MyException.class)
public ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
HttpStatus status = getStatus(request);
return new ResponseEntity<>(new MyErrorBody(status.value(), ex.getMessage()), status);
}
private HttpStatus getStatus(HttpServletRequest request) {
Integer code = (Integer) request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
HttpStatus status = HttpStatus.resolve(code);
return (status != null) ? status : HttpStatus.INTERNAL_SERVER_ERROR;
}
}
</code>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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.