写点什么

从 SpringBoot 源码看资源映射原理

  • 2021 年 11 月 11 日
  • 本文字数:3321 字

    阅读完需:约 11 分钟

上边的注释写的很清楚,重写这个方法来增加一个静态资源的映射。那么具体怎么写呢?


我们再按照注释看一下 ResourceHandlerRegistry 的源码,重点看一下对这个类的注释,如下。


/* <p>To create a resource handler, use {@link #addResourceHandler(String...)} providing the URL path patterns


/ * for which the handler should be invoked to serve static resources (e.g. {@code "/resources/**"}).


大概意思就是为了创建资源的处理器,要调用 addResourceHandler 方法来提供 url 的表达式,这个方法是为了服务静态资源的(ps:英语水平也一般,了解大意即可)


然后我们去看 addResourceHandler 方法:


/**


  • Add a resource handler for serving static resources based on the specified URL path patterns.

  • The handler will be in


【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


voked for every incoming request that matches to one of the specified


  • path patterns.

  • <p>Patterns like {@code "/static/**"} or {@code "/css/{filename:\w+\.css}"} are allowed.

  • See {@link org.springframework.util.AntPathMatcher} for more details on the syntax.

  • @return a {@link ResourceHandlerRegistration} to use to further configure the

  • registered resource handler


*/


public ResourceHandlerRegistration addResourceHandler(String... pathPatterns) {


ResourceHandlerRegistration registration = new ResourceHandlerRegistration(pathPatterns);


this.registrations.add(registration);


return registration;


}


我们看到这个方法执行后返回了一个新的类 ResourceHandlerRegistration


那我们再来看一下这个类中的核心方法


/**


  • Add one or more resource locations from which to serve static content.

  • Each location must point to a valid directory. Multiple locations may

  • be specified as a comma-separated list, and the locations will be checked

  • for a given resource in the order specified.

  • <p>For example, {{@code "/"}, {@code "classpath:/META-INF/public-web-resources/"}}

  • allows resources to be served both from the web application root and

  • from any JAR on the classpath that contains a

  • {@code /META-INF/public-web-resources/} directory, with resources in the

  • web application root taking precedence.

  • <p>For {@link org.springframework.core.io.UrlResource URL-based resources}

  • (e.g. files, HTTP URLs, etc) this method supports a special prefix to

  • indicate the charset associated with the URL so that relative paths

  • appended to it can be encoded correctly, e.g.

  • {@code [charset=Windows-31J]https://example.org/path}.

  • @return the same {@link ResourceHandlerRegistration} instance, for

  • chained method invocation


*/


public ResourceHandlerRegistration addResourceLocations(String... resourceLocations) {


this.locationValues.addAll(Arrays.asList(resourceLocations));


return this;


}


上边注释的大意就是增加一个或者多个静态资源路径,并举了一些例子。源码我们就看到这里。


所以我们可以像这样实现资源的映射:


import org.springframework.context.annotation.Configuration;


import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;


import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;


/**


  • @author liumeng

  • @Date: 2020/9/25 09:20

  • @Description:


*/


@Configuration


public class SpringMvcConfig extends WebMvcConfigurationSupport {


@Override


protected void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**").addResourceLocations("/");


}


}


关于 SpringMVC 中的资源映射部分就介绍到这,那么我们继续来看 SpringBoot 的资源映射吧。


SpringBoot 的资源映射


===================


其实 SpringBoot 的资源映射也是一脉相承的,当我们初始化一个 SpringBoot 项目后,静态资源会默认存在 resource/static 目录中,那么 SpringBoot 的底层是怎么实现的呢,接下来我们就去源码里探索一下。


SpringBoot 的源码在 WebMvcAutoConfiguration 这个类中,我们发现了熟悉的代码:


@Override


public void addResourceHandlers(ResourceHandlerRegistry registry) {


if (!this.resourceProperties.isAddMappings()) {


logger.debug("Default resource handling disabled");


return;


} Duration cachePeriod = this.resourceProperties.getCache().getPeriod();


CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();


if (!registry.hasMappingForPattern("/webjars/**")) {


customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")


.addResourceLocations("classpath:/META-INF/resources/webjars/")


.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); } String staticPathPattern = this.mvcProperties.getStaticPathPattern();


if (!registry.hasMappingForPattern(staticPathPattern)) {


customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern) .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))


.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); } }


这里面我们重点看下边这部分


String staticPathPattern = this.mvcProperties.getStaticPathPattern();


if (!registry.hasMappingForPattern(staticPathPattern)) {


customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern) .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))


.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); }


我们看一下 getStaticPathPattern()方法的实现,发现获得的就是


/**


  • Path pattern used for static resources.


*/


private String staticPathPattern = "/**";


这个属性的值,默认是/**。


然后我们再看 this.resourceProperties.getStaticLocations()方法,发现获得的是


private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;


而 CLASSPATH_RESOURCE_LOCATIONS 是一个常量,值如下:


private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",


"classpath:/resources/", "classpath:/static/", "classpath:/public/" };


在这里我们看到了四个值,static 就是其中一个,到这里我们就明白了 SpringBoot 的静态资源为什么会存在 resource/static 这个目录下,而且放在以上 4 个目录中是都可以读取到的。


实际上 SpringBoot 默认的静态资源是 5 个,我们再来看 getResourceLocations 方法,如下:


static String[] getResourceLocations(String[] staticLocations) {


String[] locations = new String[staticLocations.length + SERVLET_LOCATIONS.length];


System.arraycopy(staticLocations, 0, locations, 0, staticLocations.length);


System.arraycopy(SERVLET_LOCATIONS, 0, locations, staticLocations.length, SERVLET_LOCATIONS.length);


return locations;


}


可以看到,除了我们之前看到的 4 个路径,这个方法里还新增了一个 SERVLET_LOCATIONS 的路径,点进去看一下


private static final String[] SERVLET_LOCATIONS = { "/" };


发现就是一个"/"。


所以实际上 SpringBoot 的默认静态资源路径有 5 个:


"classpath:/META-INF/resources/" , "classpath:/resources/", "classpath:/static/", "classpath:/public/",“/”


自定义配置


=========


好了,到现在我们已经知道了 SpringBoot 的默认资源映射来源,那么我们如何配置自定义的资源映射路径呢?

评论

发布
暂无评论
从SpringBoot源码看资源映射原理