首页>>后端>>Spring->Spring MVC之注解@EnableWebMvc

Spring MVC之注解@EnableWebMvc

时间:2023-11-30 本站 点击:1

前言

其实我接触Java web开发比较晚,这句话的意思就是,我做开发的时候就使用的是比较新的技术了,比如spring boot,从来没用过ssh那一套,虽然用了spring mvc,但也是基于spring boot封装好的。

当然了,这有好处,也有坏处,好处是跟上了时代的潮流,坏处是对于被封装的那一套了解不够深刻。

今天在翻某些框架封装的源码时候,看到一些WEB项目的配置类继承了WebMvcConfigurerAdapter类,然后自定义了一些配置。另外在这个类还有这个注解:@EnableWebMvc。

然后产生了两个疑问:

1.想要自定义spring mvc的配置为什么继承WebMvcConfigurerAdapter类

2.@EnableWebMvc注解起什么用

带着这两个疑问,准备一探究竟

为什么要继承WebMvcConfigurerAdapter

首先说明下,spring mvc有几个核心组件,这些组件的配置都是可扩展的。\ 这几个核心组件不是本文的重点,也不做强调,需要了解的可以查阅相关资料。

我以前看过《看透Spring MVC源代码分析与实践》作者:韩路彪,这本书中讲解了spring mvc的九大组件,感兴趣的可以看下。

那么问题来了,如果想自定义这些配置,为什么要继承WebMvcConfigurerAdapter类。查看了其中一些类的注释,并不是一定要继承这个类,但是如果想自定义一些高级配置,建议继承它,什么算高级?嘿嘿。

先介绍下这个类,这个类实现了WebMvcConfigurer接口的所有方法(都是空实现),这里提一下WebMvcConfigurer接口,类的注释上是这样说明的:

定义回调方法,以通过{@code @EnableWebMvc}自定义启用Spring MVC的基于Java的配置。\ {@code @EnableWebMvc}已注释的配置类可以实现此接口的回调,并有机会自定义默认配置。 考虑扩展{@link WebMvcConfigurerAdapter},它提供所有接口方法的存根实现。

这几句注释在我看来有下面几个意思:

使用@EnableWebMvc注解启用spring mvc的基于java config的配置

实现WebMvcConfigurer接口的方法可以自定义spring mvc的配置

对于第2个意思,建议采用继承WebMvcConfigurerAdapter类来实现

如果想要让继承WebMvcConfigurerAdapter的自定义配置的子类起作用,那这个类应该是配置类(比如加上注解@Configuration,毕竟这个类应该托管到spring 容器内,spring mvc才会知道这个子类,要不这些自定义配置怎么起作用)

也就是说,想要启用spring mvc的时候,应用使用注解@EnableWebMvc启用spring mvc的配置,另外,如果想自定义这些配置,就使用一个可以托管到spring容器的配置类,继承WebMvcConfigurerAdapter类并重写需要自定义配置的那些方法。

到这里, 我又产生了几个疑问:

Q1. 我继承了WebMvcConfigurerAdapter类并重写需要自定义配置的那些方法,但是spring mvc是怎么知道的

Q2. spring mvc怎么知道我要自定义哪些配置,我自定义的配置会不会导致默认配置不可用

Q3. 这个自定义配置的子类是怎么和spring mvc关联的

这些问题的答案,应该就在@EnableWebMvc注解这里。所以,看下文

@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@interfaceEnableWebMvc{}

重点在于:@Import(DelegatingWebMvcConfiguration.class)这里,这是基于java config格式的配置类的导入,然后看下DelegatingWebMvcConfiguration的源码:

@ConfigurationpublicclassDelegatingWebMvcConfigurationextendsWebMvcConfigurationSupport

那就明白了: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类的部分源码,作个解释:

@ConfigurationpublicclassDelegatingWebMvcConfigurationextendsWebMvcConfigurationSupport{privatefinalWebMvcConfigurerCompositeconfigurers=newWebMvcConfigurerComposite();//注意看这里,这里把spring容器的所有实现了WebMvcConfigurer接口的类的bean作为一个集合//变量注入到了这里。//这就意味着,我们需要自定义springmvc配置的那些配置类,都会被注入到这里//这样就可以把所有配置(包括我们自定义的配置添加进去)@Autowired(required=false)publicvoidsetConfigurers(List<WebMvcConfigurer>configurers){if(!CollectionUtils.isEmpty(configurers)){this.configurers.addWebMvcConfigurers(configurers);}}@OverrideprotectedvoidconfigurePathMatch(PathMatchConfigurerconfigurer){this.configurers.configurePathMatch(configurer);}@OverrideprotectedvoidconfigureContentNegotiation(ContentNegotiationConfigurerconfigurer){this.configurers.configureContentNegotiation(configurer);}@OverrideprotectedvoidconfigureAsyncSupport(AsyncSupportConfigurerconfigurer){this.configurers.configureAsyncSupport(configurer);}@OverrideprotectedvoidconfigureDefaultServletHandling(DefaultServletHandlerConfigurerconfigurer){this.configurers.configureDefaultServletHandling(configurer);}//...}

不用太多,上面几行就明白了。

关键在于DelegatingWebMvcConfiguration类的这个属性上:

privatefinalWebMvcConfigurerCompositeconfigurers=newWebMvcConfigurerComposite();//看下WebMvcConfigurerComposite类的部分源码://可以看到这个类有个属性delegates,是个WebMvcConfigurer接口的实现类的集合classWebMvcConfigurerCompositeimplementsWebMvcConfigurer{privatefinalList<WebMvcConfigurer>delegates=newArrayList<WebMvcConfigurer>();publicvoidaddWebMvcConfigurers(List<WebMvcConfigurer>configurers){if(!CollectionUtils.isEmpty(configurers)){this.delegates.addAll(configurers);}}@OverridepublicvoidconfigurePathMatch(PathMatchConfigurerconfigurer){for(WebMvcConfigurerdelegate:this.delegates){delegate.configurePathMatch(configurer);}}@OverridepublicvoidconfigureContentNegotiation(ContentNegotiationConfigurerconfigurer){for(WebMvcConfigurerdelegate: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就会加载自定义的和默认的,看下源码就明白了:

/***Providesaccesstotheshared{@linkHttpMessageConverter}susedbythe*{@linkRequestMappingHandlerAdapter}andthe*{@linkExceptionHandlerExceptionResolver}.*Thismethodcannotbeoverridden.*Use{@link#configureMessageConverters(List)}instead.*Alsosee{@link#addDefaultHttpMessageConverters(List)}thatcanbe*usedtoadddefaultmessageconverters.*/protectedfinalList<HttpMessageConverter<?>>getMessageConverters(){if(this.messageConverters==null){this.messageConverters=newArrayList<HttpMessageConverter<?>>();configureMessageConverters(this.messageConverters);if(this.messageConverters.isEmpty()){//这里如果非空的就不加载默认配置了,注释上也有解释addDefaultHttpMessageConverters(this.messageConverters);}extendMessageConverters(this.messageConverters);}returnthis.messageConverters;}

其它几个组件,有兴趣可以查阅相关资料,或者翻下源码了解下。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/Spring/4458.html