admin管理员组文章数量:1794759
spring mvc之注解@EnableWebMvc
前言
其实我接触Java web开发比较晚,这句话的意思就是,我做开发的时候就使用的是比较新的技术了,比如spring boot,从来没用过ssh那一套,虽然用了spring mvc,但也是基于spring boot封装好的。
当然了,这有好处,也有坏处,好处是跟上了时代的潮流,坏处是对于被封装的那一套了解不够深刻。
今天在翻某些框架封装的源码时候,看到一些WEB项目的配置类继承了WebMvcConfigurerAdapter类,然后自定义了一些配置。另外在这个类还有这个注解:@EnableWebMvc。
然后产生了两个疑问:
1. 想要自定义spring mvc的配置为什么继承WebMvcConfigurerAdapter类
2. @EnableWebMvc注解起什么用
带着这两个疑问,准备一探究竟
1. 为什么要继承WebMvcConfigurerAdapter首先说明下,spring mvc有几个核心组件,这些组件的配置都是可扩展的。这几个核心组件不是本文的重点,也不做强调,需要了解的可以查阅相关资料。我以前看过《看透Spring MVC源代码分析与实践》作者:韩路彪,这本书中讲解了spring mvc的九大组件,感兴趣的可以看下。
那么问题来了,如果想自定义这些配置,为什么要继承WebMvcConfigurerAdapter类。查看了其中一些类的注释,并不是一定要继承这个类,但是如果想自定义一些高级配置,建议继承它,什么算高级?嘿嘿。
先介绍下这个类,这个类实现了WebMvcConfigurer接口的所有方法(都是空实现),这里提一下WebMvcConfigurer接口,类的注释上是这样说明的:
定义回调方法,以通过{@code @EnableWebMvc}自定义启用Spring MVC的基于Java的配置。 {@code @EnableWebMvc}已注释的配置类可以实现此接口的回调,并有机会自定义默认配置。 考虑扩展{@link WebMvcConfigurerAdapter},它提供所有接口方法的存根实现。
这几句注释在我看来有下面几个意思:
1. 使用@EnableWebMvc注解启用spring mvc的基于java config的配置
2. 实现WebMvcConfigurer接口的方法可以自定义spring mvc的配置
3. 对于第2个意思,建议采用继承WebMvcConfigurerAdapter类来实现
4. 如果想要让继承WebMvcConfigurerAdapter的自定义配置的子类起作用,那这个类应该是配置类(比如加上注解@Configuration,毕竟这个类应该托管到spring 容器内,spring mvc才会知道这个子类,要不这些自定义配置怎么起作用)
也就是说,想要启用spring mvc的时候,应用使用注解@EnableWebMvc启用spring mvc的配置,另外,如果想自定义这些配置,就使用一个可以托管到spring容器的配置类,继承WebMvcConfigurerAdapter类并重写需要自定义配置的那些方法。
到这里, 我又产生了几个疑问:
Q1. 我继承了WebMvcConfigurerAdapter类并重写需要自定义配置的那些方法,但是spring mvc是怎么知道的
Q2. spring mvc怎么知道我要自定义哪些配置,我自定义的配置会不会导致默认配置不可用
Q3. 这个自定义配置的子类是怎么和spring mvc关联的
这些问题的答案,应该就在@EnableWebMvc注解这里。所以,看下文
2. @EnableWebMvc注解起什么用@EnableWebMvc注解起什么用?先看下源码中第一行的注解说明:
将此注解添加到{@code @Configuration}类可从{@link WebMvcConfigurationSupport}导入Spring MVC配置
也就是说,这个注解应当加到有@Configuration注解的类上(意思是这个类应当是托管到spring容器的配置类),然后就可以从从{@link WebMvcConfigurationSupport}导入Spring MVC配置,问题在这个WebMvcConfigurationSupport类上。
再看下@EnableWebMvc注解类的源码:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(DelegatingWebMvcConfiguration.class) public @interface EnableWebMvc { }重点在于:@Import(DelegatingWebMvcConfiguration.class)这里,这是基于java config格式的配置类的导入,然后看下DelegatingWebMvcConfiguration的源码:
@Configuration public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport那就明白了:DelegatingWebMvcConfiguration是继承了WebMvcConfigurationSupport的配置类。
现在先来看下WebMvcConfigurationSupport是什么,注释是这样解释的:
这是提供MVC Java配置背后的配置的主类。 通常通过将{@link EnableWebMvc @EnableWebMvc}添加到应用程序{@link Configuration @Configuration}类来导入它。 另一种选择 高级选项是直接从此类扩展并根据需要覆盖方法,记住将{@link Configuration @Configuration}添加到子类和{@link Bean @Bean}以覆盖{@link Bean @Bean}方法。 有关更多详细信,请参阅{@link EnableWebMvc @EnableWebMvc}的Javadoc。
这个WebMvcConfigurationSupport类的作用呢,其实提供了上文提到的spring mvc的几个核心组件的能力。如果想要从此类扩展,只需要继承并重写它的一些方法(有兴趣的可以看下这个类的源码)。
现在就是,DelegatingWebMvcConfiguration类继承了WebMvcConfigurationSupport类并重写了它的一些方法,并且DelegatingWebMvcConfiguration类是一个配置类被托管了spring容器,重点来了:
这里说明了@EnableWebMvc注解的一个作用:
1. 启用spring mvc的这几个核心组件提供的能力(就是启用了spring mvc)
如果还不明白,这里解释下:上文说了,@EnableWebMvc注解需要用在一个可以注册到spring容器的配置类上,然后@EnableWebMvc注解导入了DelegatingWebMvcConfiguration配置类,这个类继承了WebMvcConfigurationSupport类提供的spring mvc各个组件的能力并且这个类也被注册到了spring容器。
那么,@EnableWebMvc注解和自定义配置的关系在哪,我认为这算是@EnableWebMvc注解提供的第二个作用:
2. 支持自定义spring mvc配置的能力
而它的这个能力,关键在于DelegatingWebMvcConfiguration配置类,上文说了DelegatingWebMvcConfiguration类继承自WebMvcConfigurationSupport类并重写了它的一些方法,就是它重写的这些方法,允许了我们增加自定义配置。
看一下DelegatingWebMvcConfiguration类的部分源码,作个解释:
@Configuration public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport { private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite(); // 注意看这里,这里把spring容器的所有实现了WebMvcConfigurer接口的类的bean作为一个集合 // 变量注入到了这里。 // 这就意味着,我们需要自定义spring mvc配置的那些配置类,都会被注入到这里 // 这样就可以把所有配置(包括我们自定义的配置添加进去) @Autowired(required = false) public void setConfigurers(List<WebMvcConfigurer> configurers) { if (!CollectionUtils.isEmpty(configurers)) { this.configurers.addWebMvcConfigurers(configurers); } } @Override protected void configurePathMatch(PathMatchConfigurer configurer) { this.configurers.configurePathMatch(configurer); } @Override protected void configureContentNegotiation(ContentNegotiationConfigurer configurer) { this.configurers.configureContentNegotiation(configurer); } @Override protected void configureAsyncSupport(AsyncSupportConfigurer configurer) { this.configurers.configureAsyncSupport(configurer); } @Override protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { this.configurers.configureDefaultServletHandling(configurer); } //... }不用太多,上面几行就明白了。
关键在于DelegatingWebMvcConfiguration类的这个属性上:
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite(); // 看下WebMvcConfigurerComposite类的部分源码: //可以看到这个类有个属性delegates,是个WebMvcConfigurer接口的实现类的集合 class WebMvcConfigurerComposite implements WebMvcConfigurer { private final List<WebMvcConfigurer> delegates = new ArrayList<WebMvcConfigurer>(); public void addWebMvcConfigurers(List<WebMvcConfigurer> configurers) { if (!CollectionUtils.isEmpty(configurers)) { this.delegates.addAll(configurers); } } @Override public void configurePathMatch(PathMatchConfigurer configurer) { for (WebMvcConfigurer delegate : this.delegates) { delegate.configurePathMatch(configurer); } } @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { for (WebMvcConfigurer delegate : this.delegates) { delegate.configureContentNegotiation(configurer); } } //... }注意看下,我上面贴的两段代码中加的一些中文注释。结合起来一看,这样就明白了,DelegatingWebMvcConfiguration类会把所有实现了接口WebMvcConfigurer的类(子类也是,这是java语法,就不说了)包括我们那些托管到spring容器的自定义的配置类(因为也实现了它)都会把这些配置加上。
这也就是解释了第1节中提到的Q1、Q3的问题:我的配置类注册到了spring容器中,spring通过自动注入的方式把所有WebMvcConfigurer接口的实现类注入到了DelegatingWebMvcConfiguration的configurers属性中,在WebMvcConfigurerComposite类把这些配置都给配置上。然后回调那些实现了WebMvcConfigurer接口的实现类,最终将我们自定义的配置都给加上。
现在,就剩Q2这个问题了,spring mvc怎么知道我自定义哪些配置了,在WebMvcConfigurerComposite类回调我们重写方法的接口时,如果我们重写了需要自定义配置的方法,自然就加上了,现在的问题是第二个,如果自定义了配置,是否会加载默认配置?这个就看自定义谁的配置了,比如HttpMessageConverter,如果在重写了方法configMessageConverters自定义了配置,就不会加载默认配置,如果重写的方法是extendMessageContertes就会加载自定义的和默认的,看下源码就明白了:
/** * Provides access to the shared {@link HttpMessageConverter}s used by the * {@link RequestMappingHandlerAdapter} and the * {@link ExceptionHandlerExceptionResolver}. * This method cannot be overridden. * Use {@link #configureMessageConverters(List)} instead. * Also see {@link #addDefaultHttpMessageConverters(List)} that can be * used to add default message converters. */ protected final List<HttpMessageConverter<?>> getMessageConverters() { if (this.messageConverters == null) { this.messageConverters = new ArrayList<HttpMessageConverter<?>>(); configureMessageConverters(this.messageConverters); if (this.messageConverters.isEmpty()) { // 这里如果非空的就不加载默认配置了,注释上也有解释 addDefaultHttpMessageConverters(this.messageConverters); } extendMessageConverters(this.messageConverters); } return this.messageConverters; }其它几个组件,有兴趣可以查阅相关资料,或者翻下源码了解下。
纯粹是自已瞎研究,有问题欢迎及时指正。
本文标签: 注解springMVCEnableWebMvc
版权声明:本文标题:spring mvc之注解@EnableWebMvc 内容由林淑君副主任自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.xiehuijuan.com/baike/1686616769a86660.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论