Spring 全家桶之 Spring Boot 2.6.4(五)- WebMvcAutoConfiguration(Part C)

2022-08-24 14:59:18 浏览数 (1)

三、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 and BeanNameViewResolver beans.
  • Support for serving static resources, including support for WebJars (covered later in this document).
  • Automatic registration of ConverterGenericConverter, and Formatter 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 and BeanNameViewResolver 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 ConverterGenericConverter, and Formatter 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 the spring.mvc.message-codes-resolver-format property PREFIX_ERROR_CODE or POSTFIX_ERROR_CODE, Spring Boot creates one for you (see the enumeration in DefaultMessageCodesResolver.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模块所有的自动配置。

0 人点赞