@EnableWebMvc 与 @EnableAutoConfiguration 的关系

本文解析了Spring Boot中Web MVC自动配置的工作原理,对比了@EnableAutoConfiguration与@EnableWebMvc的区别,介绍了如何通过自定义WebMvcConfigurer实现HTTP消息转换器的定制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先讲自动配置:@EnableAutoConfiguration,引入两个 JAVA 类

@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

}
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {

}

目前还不清楚这两个类的原理,但是可以知道的是,Spring 通过这两个类查找所有 JAR 包的 classpath:META-INF/spring.factories,找到 spring-boot-autoconfigure-xxx.jar 的 META-INF/spring.factories,并包含如下内容

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
......
org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,\
......

由此,Spring 加载了 WebMvc 的自动配置类

@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 {
    //......
}

值得注意的是 @ConditionalOnMissingBean(WebMvcConfigurationSupport.class),记住这个注解条件,请看以下 Spring 继承体系

这里写图片描述

记住这个继承关系,接着再来看 @EnableWebMvc,它引入了一个 Spring JavaConfig 类

@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

Spring 会加载 DelegatingWebMvcConfiguration.class 这个配置类,由之前的继承体系我们得知,它是 WebMvcConfigurationSupport 的子类,根据先前看到的自动配置的注解条件:只有当 WebMvcConfigurationSupport 这个 Bean 不存在时才加载 WebMvc 的自动配置类,否则忽略;换句话说,DelegatingWebMvcConfiguration.class 的加载取消了 WebMvc 的自动配置,也可以说 @EnableWebMvc 强制使用了另一套配置,而非 @EnableAutoConfiguration 指引的自动配置


呢么 @EnableWebMvc 有什么好处么?当然有,WebMvcConfigurationSupport(DelegatingWebMvcConfiguration 的父类) 定义了一套创建 Bean 的标准化流程,例如 RequestMappingHandlerMapping、resourceHandlerMapping、HttpMessageConverter 等等,并通过 “模板方法模式” 将其过程开放给子类,以 HttpMessageConverter 为例,请看 WebMvcConfigurationSupport 的 getMessageConverters()

protected final List<HttpMessageConverter<?>> getMessageConverters() {
    if (this.messageConverters == null) {
        this.messageConverters = new ArrayList<HttpMessageConverter<?>>();
        //这个就是模板方法,是抽象方法,必须由子类重写
        configureMessageConverters(this.messageConverters);
        if (this.messageConverters.isEmpty()) {
            //如果用户未定义任何 messageConverters,则进行默认初始化
            //默认初始化包含了 ByteArrayHttpMessageConverter、ResourceHttpMessageConverter 等
            addDefaultHttpMessageConverters(this.messageConverters);
        }
        //钩子方法
        extendMessageConverters(this.messageConverters);
    }
    return this.messageConverters;
}

//模板方法是抽象的,必须由子类重写
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
}

可以看到,这就是创建 MessageConverters 的标准化流程,再看 @EnableWebMvc 导入的 DelegatingWebMvcConfiguration(即 WebMvcConfigurationSupport 子类)是如何重写 该模板方法的

@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    this.configurers.configureMessageConverters(converters);
}

可以看到,它直接把所有的 HttpMessageConverter 交给 this.configurers 进行处理,无论是添加还是删除,是修改还是无所作为,这都是可行的,注意,这里暗示了我们开发者介入的契机,呢么 this.configurers 又是什么呢

private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();


@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
    if (!CollectionUtils.isEmpty(configurers)) {
        this.configurers.addWebMvcConfigurers(configurers);
    }
}

简单来讲,WebMvcConfigurerComposite 就是一个容纳许多 WebMvcConfigurer 的容器,Spring 通过 @Autowired 来自动注入所有的 WebMvcConfigurer,并全部添加进容器里;这意味着,我们可以定义任意多的 WebMvcConfigurer,它们全部都会被纳入容器中,并依次接受 Spring 分派所有的 HttpMessageConverter 来处理,我们可以在处理中添加我们自己想要的 HttpMessageConverter,再来看一次该模板方法代码

@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    this.configurers.configureMessageConverters(converters);
}

configurers 只是个容器,这里可能会被误导,查看其源码

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    for (WebMvcConfigurer delegate : this.delegates) {
        delegate.configureMessageConverters(converters);
    }
}

很明显,它依次调用容器中所有的 WebMvcConfigurer 的 configureMessageConverters(),所以我们要做的是:定义一个或多个 Bean 继承 WebMvcConfigurer 并重写 configureMessageConverters(),在这里面添加我们想要的 HttpMessageConverter,然后等着被自动注入,被模板方法依次调用,我们的奇思妙想就成功了,注意,一般只需要重写很少的抽象方法,因此推荐继承 WebMvcConfigurer 的子类 WebMvcConfigurerAdapter,并重写有需要的一个或几个方法

@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {

    // 自定义 JSON 转换工具
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(fastJsonHttpMessageConverterEx());
        super.configureMessageConverters(converters);
    }

    @Bean
    public FastJsonHttpMessageConverterEx fastJsonHttpMessageConverterEx() {
        return new FastJsonHttpMessageConverterEx();
    }

}

注意 @Configuration 是必要的,只有这样才能将其装配成 Bean,进而被 @Autowired 自动注入

@EnableWebMvcSpring框架中的一个注解,用于启用Spring MVC的配置。它的主要作用是启用默认的Spring MVC配置,并允许开发者在需要时进行自定义配置。通过使用@EnableWebMvc,开发者可以快速配置Spring MVC,而无需手动配置各种Bean。 以下是@EnableWebMvc的一些主要功能: 1. **启用Spring MVC默认配置**:@EnableWebMvc会自动注册一些默认的Bean,如RequestMappingHandlerMapping、RequestMappingHandlerAdapter等,这些Bean是Spring MVC正常运行所必需的。 2. **自定义配置**:通过实现WebMvcConfigurer接口,开发者可以自定义Spring MVC的配置。例如,可以添加拦截器、格式化器、视图控制器等。 3. **灵活性**:@EnableWebMvc提供了灵活性,使得开发者可以在默认配置的基础上进行扩展和定制,以满足特定的需求。 下面是一个使用@EnableWebMvc的示例: ```java import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration @EnableWebMvc public class WebConfig implements WebMvcConfigurer { // 自定义配置方法 @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MyInterceptor()); } // 其他自定义配置方法 } ``` 在这个示例中,@EnableWebMvc启用了Spring MVC的默认配置,并通过实现WebMvcConfigurer接口进行了一些自定义配置,如添加了一个拦截器。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值