我们从两个角度研究@EnableWebMvc:

  1. @EnableWebMvc的使用
  2. @EnableWebMvc的底层原理
@EnableWebMvc的使用

@EnableWebMvc需要和java配置类结合起来才能生效,其实Spring有好多@Enablexxxx的注解,其生效方式都一样,通过和@Configuration结合、使得@Enablexxxx中的配置类(大多通过@Bean注解)注入到Spring IoC容器中。

理解这一配置原则,@EnableWebMvc的使用其实非常简单。

我们还是使用前面文章的案例进行配置。

新增配置类

在org.example.configuration包下新增一个配置类:

@Configuration@EnableWebMvc@ComponentScan({"org.example.controller"})public class MvcConfiguration{@Overridepublic void extendMessageConverters(List<HttpMessageConverter> converters) {for(HttpMessageConverter httpMessageConverter:converters){if(StringHttpMessageConverter.class.isAssignableFrom(httpMessageConverter.getClass())){((StringHttpMessageConverter)httpMessageConverter).setDefaultCharset(Charset.forName("UTF-8"));}}}}

配置类增加controller的包扫描路径,添加@EnableWebMvc注解,其他不需要干啥。

简化web.xml

由于使用了@EnableWebMvc,所以web.xml可以简化,只需要启动Spring IoC容器、添加DispatcherServlet配置即可

contextConfigLocationclasspath:applicationContext.xmlorg.springframework.web.context.ContextLoaderListenerdispatcherServletorg.springframework.web.servlet.DispatcherServletcontextConfigLocationclasspath:springmvc.xml1dispatcherServlet/
applicationContext.xml

Spring IoC容器的配置文件,指定包扫描路径即可:

Springmvc.xml

springmvc.xml文件也可以简化,只包含一个视图解析器及静态资源解析的配置即可,其他的都交给@EnableWebMvc即可:

测试

添加一个controller:

@Controllerpublic classHelloWorldController {@GetMapping(value="/hello")@ResponseBodypublic String hello(ModelAndView model){return "

@EnableWebMvc 你好

";}}

启动应用,测试:

发现有中文乱码。

解决中文乱码

参考上一篇文章,改造一下MvcConfiguration配置文件,实现WebMvcConfigurer接口、重写其extendMessageConverters方法:

@Configuration@EnableWebMvc@ComponentScan({"org.example.controller"})public class MvcConfiguration implements WebMvcConfigurer{public MvcConfiguration(){System.out.println("mvc configuration constructor...");}//通过@EnableWebMVC配置的时候起作用,@Overridepublic void extendMessageConverters(List<HttpMessageConverter

重启系统,测试:

中文乱码问题已解决。

问题:@EnableWebMvc的作用?

上述案例已经可以正常运行可,我们可以看到web.xml、applicationContext.xml以及springmvc.xml等配置文件都还在,一个都没少。

那么@EnableWebMvc究竟起什么作用?

我们去掉@EnableWebMvc配置文件试试看:项目中删掉MvcConfiguration文件。

重新启动项目,访问localhost:8080/hello,报404!

回忆一下MvcConfiguration文件中定义了controller的包扫描路径,现在MvcConfiguration文件被我们直接删掉了,controller的包扫描路径需要以其他方式定义,我们重新修改springmvc.xml文件,把controller包扫描路径加回来。

同时,我们需要把SpringMVC的注解驱动配置加回来:

以上两行加入到springmvc.xml配置文件中,重新启动应用:

应用可以正常访问了,中文乱码问题请参考上一篇文章,此处忽略。

因此我们是否可以猜测:@EnableWebMvc起到的作用等同于配置文件中的: " />@EnableWebMvc的底层原理

其实Spring的所有@Enablexxx注解的实现原理基本一致:和@Configuration注解结合、通过@Import注解引入其他配置类,从而实现向Spring IoC容器注入Bean。

@EnableWebMvc也不例外。

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import(DelegatingWebMvcConfiguration.class)public @interface EnableWebMvc {}

@EnableWebMvc引入了DelegatingWebMvcConfiguration类。看一眼DelegatingWebMvcConfiguration类,肯定也加了@Configuration注解的:

@Configuration(proxyBeanMethods = false)public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport { ...

DelegatingWebMvcConfiguration类扩展自WebMvcConfigurationSupport,其实DelegatingWebMvcConfiguration并没有创建bean、实际创建bean的是他的父类WebMvcConfigurationSupport。

WebMvcConfigurationSupport按顺序注册如下HandlerMappings:

  1. RequestMappingHandlerMapping ordered at 0 for mapping requests to annotated controller methods.
  2. HandlerMapping ordered at 1 to map URL paths directly to view names.
  3. BeanNameUrlHandlerMapping ordered at 2 to map URL paths to controller bean names.
  4. HandlerMapping ordered at Integer.MAX_VALUE-1 to serve static resource requests.
  5. HandlerMapping ordered at Integer.MAX_VALUE to forward requests to the default servlet.

并注册了如下HandlerAdapters:

  1. RequestMappingHandlerAdapter for processing requests with annotated controller methods.
  2. HttpRequestHandlerAdapter for processing requests with HttpRequestHandlers.
  3. SimpleControllerHandlerAdapter for processing requests with interface-based Controllers.

注册了如下异常处理器HandlerExceptionResolverComposite:

  1. ExceptionHandlerExceptionResolver for handling exceptions through org.springframework.web.bind.annotation.ExceptionHandler methods.
  2. ResponseStatusExceptionResolver for exceptions annotated with org.springframework.web.bind.annotation.ResponseStatus.
  3. DefaultHandlerExceptionResolver for resolving known Spring exception types

以及:

Registers an AntPathMatcher and a UrlPathHelper to be used by:

  1. the RequestMappingHandlerMapping,
  2. the HandlerMapping for ViewControllers
  3. and the HandlerMapping for serving resources

Note that those beans can be configured with a PathMatchConfigurer.

Both the RequestMappingHandlerAdapter and the ExceptionHandlerExceptionResolver are configured with default instances of the following by default:

  1. a ContentNegotiationManager
  2. a DefaultFormattingConversionService
  3. an org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean if a JSR-303 implementation is available on the classpath
  4. a range of HttpMessageConverters depending on the third-party libraries available on the classpath.

因此,@EnableWebMvc确实与 起到了类似的作用:注册SpringWebMVC所需要的各种特殊类型的bean到Spring容器中,以便在DispatcherServlet初始化及处理请求的过程中生效!

上一篇 Spring MVC 十一:中文乱码