Spring Boot为Spring MVC提供了自动配置,默认支持以下功能
- ContentNegotiatingViewResolver和BeanNameViewResolver视图解析器
- 支持静态资源,包括webjars
- 转换器的自动注册、自定义转换器GenericConverter与格式化
- 支持http消息转换(请求与响应)
- MessageCodesResolver错误消息
- 首页映射
- 图标自定义
- 自动使用ConfigurableWebBindingInitializer,博主百度了一下,它的主要作用就是初始化WebDataBinder,将请求的参数转化为对应的JavaBean,并且会结合类型、格式转换等API一起使用
SpringBoot启动时会默认加载 xxxAutoConfiguration 类(自动配置类),SpringMVC功能的自动配置类为 WebMvcAutoConfiguration
@AutoConfiguration( after = {DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class} ) @ConditionalOnWebApplication( type = Type.SERVLET ) @ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class}) @ConditionalOnMissingBean({WebMvcConfigurationSupport.class}) @AutoConfigureOrder(-2147483638) public class WebMvcAutoConfiguration { ... }
然后我们可以看到他有一个静态内部类WebMvcAutoConfigurationAdapter,可以看到这是一个配置类
@Configuration( proxyBeanMethods = false ) @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class}) // 将配置文件的相关属性和括号中的两个类进行了绑定,然后注册到容器中。WebMvcProperties和spring.mvc开头的配置、WebProperties和spring.web开头的配置 @EnableConfigurationProperties({WebMvcProperties.class, WebProperties.class}) @Order(0) public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware { ... }
然后我们发现,这个配置类只有一个有参构造器,在这种情况下,我们默认有参构造器所有参数的值都会从容器中获取
// 这里的WebProperties 和WebMvcProperties都在上面和配置进行绑定过了,如果我们没有配置该配置项,那就去类中取默认配置的值 // ListableBeanFactory beanFactory Spring的beanFactory // 其他的可以自己去了解下,博主这里没有特地去搜了 public WebMvcAutoConfigurationAdapter(WebProperties webProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvidermessageConvertersProvider, ObjectProvider resourceHandlerRegistrationCustomizerProvider, ObjectProvider dispatcherServletPath, ObjectProvider > servletRegistrations) { this.resourceProperties = webProperties.getResources(); this.mvcProperties = mvcProperties; this.beanFactory = beanFactory; this.messageConvertersProvider = messageConvertersProvider; this.resourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable(); this.dispatcherServletPath = dispatcherServletPath; this.servletRegistrations = servletRegistrations; this.mvcProperties.checkConfiguration(); }
那么我们的静态资源映射以及webjars都是在哪里进行配置的呢,我们往下看找到一个方法
public void addResourceHandlers(ResourceHandlerRegistry registry) { // 判断这个isAddMappings属性是否为false,默认值是true,如果我们在yaml文件或者properties中改为false,那么就会进这个条件语句,后面的静态资源路径以及webjars都不会生效了 if (!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); } else { // webjars的规则 this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/"); // 默认静态资源地址的处理规则 this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> { registration.addResourceLocations(this.resourceProperties.getStaticLocations()); if (this.servletContext != null) { ServletContextResource resource = new ServletContextResource(this.servletContext, "/"); registration.addResourceLocations(new Resource[]{resource}); } }); } }
那我们欢迎页是在哪里配置的呢?
我们发现,在这个WebMvcAutoConfiguration下面还有一个静态内部类EnableWebMvcConfiguration,它也是一个配置类
这里面有一个方法welcomePageHandlerMapping()
HandlerMapping(处理映射器):根据URL找到对应的处理器
@Bean public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) { WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern()); welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider)); welcomePageHandlerMapping.setCorsConfigurations(this.getCorsConfigurations()); return welcomePageHandlerMapping; }
点进WelcomePageHandlerMapping的构造方法可以看到,它的逻辑大体上为,如果welcomePage不等于null,而且staticPathPattern是默认的/**,就会去我们的静态资源文件夹找index.html,否则就去找有没有能处理/index接口的映射器
这里的staticPathPattern和spring.mvc.static-path-pattern是绑定在一起的
WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders, ApplicationContext applicationContext, Resource welcomePage, String staticPathPattern) { if (welcomePage != null && "/**".equals(staticPathPattern)) { logger.info("Adding welcome page: " + welcomePage); this.setRootViewName("forward:index.html"); } else if (this.welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) { logger.info("Adding welcome page template: index"); this.setRootViewName("index"); } }3、未完待续,明日更新