NOTE
Spring MVC Auto-Configuration Principle
1. Auto-configuration classes pre-imported by spring-boot-starter-web. 2. How custom configuration takes effect. 3. Why @EnableWebMvc disables Spring Boot MVC auto-configuration. 4. Reference.
This is a historical learning note and may contain outdated or incomplete understanding.
1. Auto-Configuration Classes Pre-Imported by spring-boot-starter-web
@WebMvcAutoconfiguration
WebMvcAutoConfigurationAdapter is the class through which Spring Boot enables Web MVC auto-configuration, as shown below.
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
WebMvcConfigurerAdapter.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {
@Configuration
@Import(EnableWebMvcConfiguration.class)// The key is this EnableWebMvcConfiguration
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
// This class extends WebMvcConfigurerAdapter
public static class WebMvcAutoConfigurationAdapter extends WebMvcConfigurerAdapter {
//...
}
}
- It contains a static inner configuration class,
WebMvcAutoConfigurationAdapter.
It extends WebMvcConfigurerAdapter: by overriding some methods, MVC can be configured.
- At the same time, it also imports a class named
EnableWebMvcConfiguration.
This class is shown below. It extends DelegatingWebMvcConfiguration [the main focus of the analysis].
@Configuration
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration
2. Principle Behind Custom Configuration Taking Effect
2.1. Inject WebMvcConfigurerComposite and List
DelegatingWebMvcConfigurationuses:
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
// The key is this
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();
@Autowired(required = false)// Indicates that method parameters are obtained from the container
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
// Take the method below as an example
@Override
protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
this.configurers.configureContentNegotiation(configurer);
}
}
2.2. Let WebMvcConfigurerComposite Call WebMvcConfigurer Methods to Customize Spring MVC
- The
setConfigurersmethod in this class uses the@Autowiredannotation, so allWebMvcConfigurerinstances in the container are injected into the parameterList<WebMvcConfigurer> configurers. - At the same time, this class also has a
WebMvcConfigurerCompositefield, which is specifically used to manage allWebMvcConfigurerinstances.
Take the configureContentNegotiation method as an example. It calls WebMvcConfigurerComposite.configureContentNegotiation. This method traverses all WebMvcConfigurer instances and invokes their configureContentNegotiation methods, as shown below.
class WebMvcConfigurerComposite implements WebMvcConfigurer {
private final List<WebMvcConfigurer> delegates = new ArrayList<WebMvcConfigurer>();
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
// Call every WebMvcConfigurer in the container, including ours and Spring Boot's
for (WebMvcConfigurer delegate : this.delegates) {
delegate.configureContentNegotiation(configurer);
}
}
}
3. Why Using @EnableWebMvc Causes Spring Boot MVC Auto-Configuration to Stop Working
First look at the class imported by EnableWebMvc, DelegatingWebMvcConfiguration.
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
This DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport, which is equivalent to importing WebMvcConfigurationSupport.
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport
Then look at the MVC auto-configuration class WebMvcAutoConfiguration.
@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
WebMvcConfigurerAdapter.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)// This class only takes effect when WebMvcConfigurationSupport is missing
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class,
ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration
3.1. Conditional Annotation Causes the Preconfiguration to Stop Working
- In fact, the
WebMvcAutoConfigurationclass thatspring-boot-starter-webuses to preconfigure MVC requires:
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class) // This class only takes effect when WebMvcConfigurationSupport is missing
- If we configure
@EnableWebMvc, it importsDelegatingWebMvcConfiguration, which extendsWebMvcConfigurationSupport. - The two conflict, so auto-configuration stops working.
3.2. How to Add Custom MVC Configuration
@Configuration
// Do not use @EnableWebMvc, otherwise MVC is fully taken over -- that is, Spring Boot auto-configuration is no longer used
public class MyWebMvcConfig extends WebMvcConfigurerAdapter// Extends WebMvcConfigurerAdapter and implements the WebMvcConfigurer interface
{
// Override the corresponding methods as needed. This allows both extension and use of the default implementation
}
Discussion
Sign in with GitHub to comment. Discussions are stored as GitHub Issues.View on GitHub