三、Spring Boot Web MVC 自动配置
Spring Boot 官方文档 Web 模块 的自动配置说明
Spring MVC Auto-configuration
Spring Boot 已经自动配置好了Spring MVC,可以使用Web Starter快速创建启动并运行。
Spring Boot 官方文档列出了以下这些关于MVC的配置
Spring Boot provides auto-configuration for Spring MVC that works well with most applications.
The auto-configuration adds the following features on top of Spring’s defaults:
- Inclusion of
ContentNegotiatingViewResolver
andBeanNameViewResolver
beans. - Support for serving static resources, including support for WebJars (covered later in this document).
- Automatic registration of
Converter
,GenericConverter
, andFormatter
beans. - Support for
HttpMessageConverters
(covered later in this document). - Automatic registration of
MessageCodesResolver
(covered later in this document). - Static
index.html
support. - Automatic use of a
ConfigurableWebBindingInitializer
bean (covered later in this document).
视图解析器
- Inclusion of
ContentNegotiatingViewResolver
andBeanNameViewResolver
beans. 自动配置了视图解析器,视图解析器的作用是根据方法的返回值得到视图对象,视图对象再决定是否需要转发或者重定向。
视图解析器源码分析,入口是org.springframework.boot.autoconfigure.web.servlet包下的 自动配置类WebMvcAutoConfiguration,所有MVC的自动配置都在该类中,该类中包含了三个返回视图解析器resolver的方法,除了一个默认的defaultViewResolver方法外,另外两个就是自动配置的ContentNegotiatingViewResolver
and BeanNameViewResolver
查看ContentNegotiatingViewResolver的resolveViewName方法是如何解析视图的
resolveViewName方法中通过getCandidateViews获取视图并保存在一个View的List中。
getCandidateViews方法会遍历所有的视图解析器来解析视图,将解析出来的视图保存到列表中
ContentNegotiatingViewResolver类的作用就是组合所有视图解析器解析视图。
ContentNegotiatingViewResolver先new了一个保存视图解析器的列表
调用视图解析器的初始化方法,通过BeanFactoryUtils从容其中获取所有的视图解析器保存在集合中
这样的话我们就可以自己给容器中添加一个视图解析器,自动的加进ContentNegotiatingViewResolver视图解析器的列表中
自定义视图解析器实现
代码语言:javascript复制public class LilithViewResolver implements ViewResolver {
@Override
public View resolveViewName(String viewName, Locale locale) throws Exception {
System.out.println("自定义的视图解析器LilithViewResolver");
return null;
}
}
通过配置类,将自定义的视图解析器注册到Spring容器中
代码语言:javascript复制@Configuration
public class ViewResolverConfig {
// 将自定义的视图解析器注册到Spring容器中
@Bean
public ViewResolver lilithViewResolver(){
return new LilithViewResolver();
}
}
debug查看容器中是否在视图解析器的列表中,在doDispatch方法上打断点
根据Debug的信息来看,自定义的视图解析器已经被添加到视图解析器的列表中了
静态资源配置
- Support for serving static resources, including support for WebJars (covered later in this document).
静态资源的配置原理和使用可以参考 Spring 全家桶之 Spring Boot 2.6.4(五)- Web Develop(Part A)中的 Spring Boot对静态资源的映射规则 部分
自动注册Converter和Formatter格式化器
- Automatic registration of
Converter
,GenericConverter
, andFormatter
beans.
类型转换器的作用是将前端请求中的String类型的数据转化成基本数据类型或者自定义对象;Formatter格式化的作用是将String时间转换成Date类型
自动配置类往容器中添加了一个组件FormattingConversionService,这个组件就包含了Converter功能和Formatter功能。
自定义格式转换器
首先定义一个注解@BoolFormat
代码语言:javascript复制@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.PARAMETER})
public @interface BooleanFormat {
}
接着定义一个转换器类BooleanFormatter,继承Formatter接口,实现格式转换功能,并将该类注册到容器中,该类会将values数组中的值全部转换true,数组之外的为false。
代码语言:javascript复制@Component
public class BooleanFormatter implements Formatter<Boolean> {
private final String[] values = {"是", "YES", "Y", "yes", "Yes", "ok", "OK", "Ok" , "好", "哦了"};
@Override
public Boolean parse(String text, Locale locale){
return Arrays.asList(values).contains(text);
}
@Override
public String print(Boolean object, Locale locale) {
return object ? "true" : "false";
}
}
再定义一个工厂类LilithBooleanFormatterFactory,继承AnnotationFormatterFactory
代码语言:javascript复制@Component
public class LilithBooleanFormatterFactory implements AnnotationFormatterFactory<BooleanFormat> {
@Resource
private BooleanFormatter booleanFormatter;
@Override
public Set<Class<?>> getFieldTypes() {
Set<Class<?>> set=new HashSet<>();
set.add(Boolean.class);
return set;
}
@Override
public Parser<?> getParser(BooleanFormat annotation, Class<?> fieldType) {
return booleanFormatter;
}
@Override
public Printer<?> getPrinter(BooleanFormat annotation, Class<?> fieldType) {
return booleanFormatter;
}
}
新建一个BoolController测试格式转换器是否能正常工作
代码语言:javascript复制@RestController
public class BoolController {
@RequestMapping("/bool")
public String hallo(@BooleanFormat Boolean value){
return value.toString();
}
}
重启应用
测试values数组以外的值,传入ooook
返回false
支持HTTP消息转换器
- Support for
HttpMessageConverters
(covered later in this document).
Spring MVC uses the
HttpMessageConverter
interface to convert HTTP requests and responses.
Spring MVC 使用HttpMessageConverter来转换HTTP请求和响应
官方文档 自定义HttpMessageConverter
自定义HttpMessageConverter的方式与自定义ViewResolver的方式一样,只需要将自定义的HttpMessageConverter加入容器中即可。
Spring Boot是如何自动配置HttpMessageConverter的?
WebMvcAutoConfiguration自动配置类中有一个WebMvcAutoConfigurationAdapter自动配置适配器,这个类的有参构造方法中导入了HttpMessageConverter
HttpMessageConverter实现了Iterable<HttpMessageConverter<?>> 接口
从容器中获取所有的HttpMessageConverter然后添加到自动配置类中
自动注册 MessageCodesResolver
- Automatic registration of
MessageCodesResolver
(covered later in this document).
Spring MVC has a strategy for generating error codes for rendering error messages from binding errors:
MessageCodesResolver
. If you set thespring.mvc.message-codes-resolver-format
propertyPREFIX_ERROR_CODE
orPOSTFIX_ERROR_CODE
, Spring Boot creates one for you (see the enumeration inDefaultMessageCodesResolver.Format
).
主要是用来定义错误代码生成规则的
MessageCodeResolver在自动配置类中的配置方式
欢迎页配置
- Static
index.html
support. 欢迎页的配置原理和使用可以参考 Spring 全家桶之 Spring Boot 2.6.4(五)- Web Develop(Part A)中的 Spring Boot 欢迎页 部分
自动使用 ConfigurableWebBindingInitializer
- Automatic use of a
ConfigurableWebBindingInitializer
bean (covered later in this document).
自动配置类中关于ConfigurableWebBindingInitializer的定义方式。可以自定义一个ConfigurableWebBindingInitializer来替换默认的。
getConfigurableWebBindingInitializer方法会首先从容器中获取ConfigurableWebBindingInitializer,如果找不到就会调用父类的getConfigurableWebBindingInitializer方法
父类中这个方法就是初始化所有的WebDataBinder,WebDataBinder的作用就是将请求数据转换成为Java Bean
initBinder就是初始化WebDataBinder的方法
org.springframework.boot.autoconfigure.web.servlet. DispatcherServletAutoConfiguration包含了Web模块所有的自动配置。