一、Spring MVC 自动配置
Spring Boot 为 Spring MVC 应用提供了自动配置。主要包括视图解析器、静态资源处理、类型转化器与格式化器、HTTP 消息转换器、静态主页的支持等。
Spring MVC 自动配置是通过 WebMvcAutoConfiguration
类实现的,如果你去看这个类的源码,一定会发现很多熟悉的配置,比如视图解析、欢迎页、请求处理器、过滤器等。
Spring Boot 还支持用户自定义这些组件,当项目启动时先检查用户有没有自定义这些组件,如果有定义就使用自定义的,当没有自定义时就默认使用自动配置的。
比如下面自定义一个支持 RESTful 的过滤器(没有实际的用途,用于说明问题)
@Configuration
public class MyHttpMethodFilter {
@Bean
public HiddenHttpMethodFilter httpMethodFilter() {
return new HiddenHttpMethodFilter();
}
}
当项目启动时,可以通过日志查看是否生效
二、扩展 Spring MVC 配置
在保持上面自动配置的基础上,Spring Boot 还支持扩展其他的组件,比如拦截器、格式化器、视图控制器等。@Configuration
注解可以用于实现这个功能,表明这是一个 WebMvcConfigurer
的配置类。当使用这个注解扩展 Spring MVC 时,不能再添加 @EnableWebMvc
注解,原因会在下面讲到。
在 Spring Boot 2.0 以前使用 WebMvcConfigurerAdapter
来扩展 Spring MVC 组件,它是一个适配器,实现自 WebMvcConfigurer
接口,里面的方法全部是空方法。目的就是让我们继承这个类,重写里面的方法。
在 Spring Boot 2.0 之后 WebMvcConfigurerAdapter
就已经过时了,并且 WebMvcConfigurer
接口也发生了变化,里面所有的方法都定义成了默认方法(default)。因此我们可以直接实现 WebMvcConfigurer
接口,重写对应的方法即可,接口中的默认方法是 jdk1.8 才支持的,所以使用时必须保证这一点。
WebMvcConfigurer
接口中可以扩展的方法
下面以拦截器为例来说明问题
自定义拦截器类 MyHandlerInterceptor
/**
* Spring Boot2.0 版本以上 HandlerInterceptor 接口中的方法全部是默认方法
* 因此这里只重写 preHandle 方法,在目标方法执行前打印一句话
*/
public class MyHandlerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
System.out.println("== preHandle ==");
return true;
}
}
Spring MVC 扩展类 WebConfiguration
@Configuration
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyHandlerInterceptor()).addPathPatterns("/**");
}
}
测试的 Controller
@RequestMapping("/test")
@ResponseBody
public String test() {
System.out.println("**************");
return "Hello Spring Boot!";
}
当访问 /test
时控制台的输出如下
三、禁用 Spring MVC 的自动配置
上面提到在使用 WebMvcConfigurer
扩展 Spring MVC 组件时,类上不能加 @EnableWebMvc
注解,原因是在加上该注解后,Spring MVC 的自动配置会失效,所有的东西都需要我们自动配置。
下面来测试一下,在 WebConfiguration
扩展类加上 @EnableWebMvc
注解
@Configuration
@EnableWebMvc
public class WebConfiguration implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyHandlerInterceptor()).addPathPatterns("/**");
}
}
下面是入口类启动日志,发现只有一个编码过滤器生效,这也可以说明编码过滤器并不属于自动配置
PS:
从这个问题也可以看出为什么 Spring Boot 受到很多 Java 开发者的喜欢,原因就是当你需要它的时候,它可以自动帮你完成很多任务,当你不需要它时,你也可以完全将它抛弃。