• 【Spring Boot】web开发相关源码分析


    一、MVC自动配置

    1、默认支持的功能

    Spring Boot为Spring MVC提供了自动配置,默认支持以下功能

    • ContentNegotiatingViewResolver和BeanNameViewResolver视图解析器
    • 支持静态资源,包括webjars
    • 转换器的自动注册、自定义转换器GenericConverter与格式化
    • 支持http消息转换(请求与响应)
    • MessageCodesResolver错误消息
    • 首页映射
    • 图标自定义
    • 自动使用ConfigurableWebBindingInitializer,博主百度了一下,它的主要作用就是初始化WebDataBinder,将请求的参数转化为对应的JavaBean,并且会结合类型、格式转换等API一起使用

    2、静态资源与首页相关源码解析

    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 {
    	...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    然后我们可以看到他有一个静态内部类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 {
    	...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    然后我们发现,这个配置类只有一个有参构造器,在这种情况下,我们默认有参构造器所有参数的值都会从容器中获取

    // 这里的WebProperties 和WebMvcProperties都在上面和配置进行绑定过了,如果我们没有配置该配置项,那就去类中取默认配置的值
    // ListableBeanFactory beanFactory Spring的beanFactory
    // 其他的可以自己去了解下,博主这里没有特地去搜了
    public WebMvcAutoConfigurationAdapter(WebProperties webProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ObjectProvider<DispatcherServletPath> dispatcherServletPath, ObjectProvider<ServletRegistrationBean<?>> 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    那么我们的静态资源映射以及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});
                }
    
            });
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    那我们欢迎页是在哪里配置的呢?
    我们发现,在这个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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    点进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");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3、未完待续,明日更新

  • 相关阅读:
    web期末网站设计大作业 奶茶店网站美食餐饮网站设计与实现(HTML+CSS+JavaScript)
    【斗罗二】再度魔改,弓老被删,冰帝武魂提前曝光,官方经费已不足
    《痞子衡嵌入式半月刊》 第 103 期
    【Linux】linux系统VIM简介_使用
    Docker的初级使用
    Python 运算符重载Demo
    揭秘光耦合器继电器:了解其功能和应用
    天玑810和天玑900哪个好 天玑810和天玑900差距
    C# 第五章『面向对象』◆第7节:多态
    成人本科毕业论文怎么写?分享自己的经验
  • 原文地址:https://blog.csdn.net/Decade0712/article/details/126004805