SpringBoot Web源码分析(一) 静态资源源码分析

层层递进的关系来分析 SpringBoot 的Web模块源码

1. SpringBoot Web源码分析(一) 静态资源源码分析

2. SpringBoot Web源码分析(二) 请求处理源码分析

3. SpringBoot Web源码分析(三) 响应处理源码分析

4. SpringBoot Web源码分析(四) 视图解析器源码分析

5. SpringBoot Web源码分析(五),拦截器和文件上传

6. SpringBoot Web源码分析(六) 异常处理和Servlet组件

7. SpringBoot Web源码分析(七) 嵌入式服务器和定制化原理

一、 静态资源访问

1. 静态资源目录

只要放在类路径下:called /static(or /public or /resources or /META-INF/resources)
访问当前项目路径/ + 静态资源名,只需要写静态资源名就能访问,springboot

原理:/**
收到请求后先去匹配 controller,如果不能处理就去交给静态资源处理器。

改变默认的静态资源位置

  web:
    resources:
      static-locations: classpath:/path

2. 静态资源访问前缀

spring:
  mvc:
    static-path-pattern: /res/**

当前项目 + static-path-pattern + 静态资源名 = 静态资源文件夹下的

二、欢迎页支持

1. 自动加载的欢迎页面

  1. 在静态资料路径下 index.html
    1. 可以配置静态资源路径
    2. 但是不可以配置静态资源的访问前缀。否则导致index.html 不能被默认访问
  2. controller 能够处理 /index 请求的controller 自动会请求

2. favicon支持

将 favicon.ico 放置在静态资源路径下,会自动将favicon.ico 作为页面小图标

三、静态资源配置原理

1. 加载配置类源码

  1. springboot启动默认加载 XXXAutoConfiguration类(自动配置类)
  2. SpringMVC功能的自动配置类是 WebMvcAutoConfiguration
@Configuration(
    proxyBeanMethods = false
)
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {}

2. 配置类生效源码

@Configuration(
        proxyBeanMethods = false
    )
    @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
    @EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class, WebProperties.class})
    @Order(0)
    public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {}

配置文件的相关属性和什么进行了绑定

如果配置中只有一个有参构造器,那么属性会自动从容器中找

// ResourceProperties 获取 spring.resources
// WebMvcProperties 获取 sprint.mvc
// ListableBeanFactory 获取bean 工厂
// ResourceHandlerRegistrationCustomizer 获取资源处理自定义器
// ...
        public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebProperties webProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ObjectProvider<DispatcherServletPath> dispatcherServletPath, ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
            this.resourceProperties = (Resources)(resourceProperties.hasBeenCustomized() ? 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();
        }

3. 资源处理的默认规则源码

这样可以看出默认规则下的SpringBoot 以什么路径作为静态资源,以及为webjar的配置

public void addResourceHandlers(ResourceHandlerRegistry registry) {
            if (!this.resourceProperties.isAddMappings()) {
                logger.debug("Default resource handling disabled");
            } else {
                Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
                CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
                if (!registry.hasMappingForPattern("/webjars/**")) {
                    this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
                }

                String staticPathPattern = this.mvcProperties.getStaticPathPattern();
                if (!registry.hasMappingForPattern(staticPathPattern)) {
                    this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl));
                }

            }
        }

4. 可以直接禁用所有静态资源

spring:
  web:
    resources:
      add-mappings: false

5. 默认资源配置源码

private static final String[] CLASSPATH_RESOURCE_LOCATIONS = 
new String[]{"classpath:/META-INF/resources/", 
"classpath:/resources/", "classpath:/static/", 
"classpath:/public/"};
    private String[] staticLocations;
    private boolean addMappings;
    private final ResourceProperties.Chain chain;
    private final ResourceProperties.Cache cache;

6. 欢迎页源码分析

我们都知道SpringBoot中有默认的欢迎页面,这里是用SpringBoot给我们提供的类 WelcomePageHandlerMapping 来进行提供的,在访问这个HanderMapping之前,其实SpringBoot 会先去访问 RequestMappingHandlerMapping,即程序员自己创建的 controller 的HandlerMapping,这也说明了我们编写的Controller的优先级是最高的(后面有详细描述)。

@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(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");
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_CX_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值