Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >从SpringBoot源码看资源映射原理

从SpringBoot源码看资源映射原理

作者头像
HUC思梦
发布于 2022-05-11 02:27:23
发布于 2022-05-11 02:27:23
5830
举报

前言

很多的小伙伴刚刚接触SpringBoot的时候,可能会遇到加载不到静态资源的情况。

比如html没有样式,图片无法加载等等。

今天王子就与大家一起看看SpringBoot中关于资源映射部分的主要源码实现。

建议环境允许的情况下,小伙伴们自己使用idea创建一个springBoot项目,跟着文章和王子一起看一看源码,更容易理解。

SSM中的资源映射

在谈SpringBoot之前,我们先回顾一下SSM中关于资源配置是如何实现的。

在SSM环境下,一般我们可以通过<mvc:resources />节点来配置不拦截静态资源,就像下边这样:

代码语言:javascript
AI代码解释
复制
<mvc:resources mapping="/js/**" location="/js/" />
<mvc:resources mapping="/css/**" location="/css/" />
<mvc:resources mapping="/img/**" location="/img/" />

这里的/**表示的是可以匹配任意层级的路径,属于ant风格表达式,感兴趣的小伙伴自行百度了解即可,所以也可以写成下面这样

代码语言:javascript
AI代码解释
复制
<mvc:resources mapping="/**" location="/" />

上边的这种配置方式是属于XML配置的方式,SpringMVC的配置方式除了XML配置,也是可以通过java代码配置的,只需要我们自己定义一个类,来继WebMvcConfigurationSupport这个类即可,我们看一下WebMvcConfigurationSupport的源码部分:

代码语言:javascript
AI代码解释
复制
    /**
     * Override this method to add resource handlers for serving static resources.
     * @see ResourceHandlerRegistry
     */
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
    }

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

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

代码语言:javascript
AI代码解释
复制
 /* <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方法:

代码语言:javascript
AI代码解释
复制
    /**
     * Add a resource handler for serving static resources based on the specified URL path patterns.
     * The handler will be invoked 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

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

代码语言:javascript
AI代码解释
复制
    /**
     * 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;
    }

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

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

代码语言:javascript
AI代码解释
复制
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这个类中,我们发现了熟悉的代码:

代码语言:javascript
AI代码解释
复制
    @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));
            }
        }

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

代码语言:javascript
AI代码解释
复制
       String staticPathPattern = this.mvcProperties.getStaticPathPattern();
            if (!registry.hasMappingForPattern(staticPathPattern)) {
                customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
                        .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
                        .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
            }

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

代码语言:javascript
AI代码解释
复制
    /**
     * Path pattern used for static resources.
     */
    private String staticPathPattern = "/**";

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

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

代码语言:javascript
AI代码解释
复制
    private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;

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

代码语言:javascript
AI代码解释
复制
    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方法,如下:

代码语言:javascript
AI代码解释
复制
    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的路径,点进去看一下

代码语言:javascript
AI代码解释
复制
    private static final String[] SERVLET_LOCATIONS = { "/" };

发现就是一个"/"。

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

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

自定义配置

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

其实我们可以直接通过application.properties配置,如下:

代码语言:javascript
AI代码解释
复制
spring.resources.static-locations=classpath:/
spring.mvc.static-path-pattern=/**

那么为什么这样配置就可以了呢,是因为相应的类上使用了下面的注解:

@ConfigurationProperties(prefix = "spring.mvc")

@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)

本文就不对这个注解再做深入研究了。感兴趣的小伙伴可以持续关注我们的后续文章。

除了通过配置文件自定义,还可以通过java代码进行配置,这种方式和我们上文说到的SpringMvc方式比较类似,只不过我们这次是实现的WebMvcConfigurer这个接口

实现方式如下:

代码语言:javascript
AI代码解释
复制
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class ResourcesConfig implements WebMvcConfigurer
{

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry)
    {
        registry.addResourceHandler( "/**").addResourceLocations("classpath:/aaa");
    }
}

有了上边文章的铺垫,相信大家对于这段代码应该秒懂了吧。

到这里,小伙伴们是否会有个疑问,WebMvcConfigurer和WebMvcConfigurationSupport有什么关系呢?

这个问题本文就不再探索了,留给大家自行探索。

总结

好了,今天王子和大家一起从SpringMVC的源码开始探索,引出了SpringBoot的资源映射配置原理。

又介绍了SpringBoot自定义资源映射路径的两种方式,相信小伙伴们会有一个比较深刻的印象了。

本文到这里就结束了,如果觉得内容对你有所帮助,那么欢迎持续关注后续文章。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-09-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
HTTP协议简述
超文本传输协议(HyperText Transfer Protocol,HTTP),是互联网应用最广泛的网络协议。最初的HTTP协议设计用于发送和接收HTML。经过发展演变成为客户端和服务器进行请求(Request)和响应(Response)的标准协议。要了解HTTP的运行过程,需要了解大体OSI模型
BUG弄潮儿
2021/02/03
4820
HTTP协议简述
五千来字小作文,是的,我们是有个HTTP。
因为这个属性JSESSIONID比较重要,存储的是sessionId,这个要是被别人拿到的话,别人就可以冒充我在网站上做某些事情了,像我自己一样请求某些数据了
java小杰要加油
2021/05/13
5340
五千来字小作文,是的,我们是有个HTTP。
关于HTTP的笔记
网上看了一篇关于HTTP的博客,觉得还不错,这里就记下来了。 参考:https://www.cnblogs.com/guguli/p/4758937.html 一、主要特点 1.支持客户/服务器模式 2.简单快速:客户向服务器请求服务时,只需请求方法和路径。(常用请求方法有GET HEAD POST) 3.灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-type加以标记 4.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户机的应答后,即断开连接
xcywt
2018/03/28
8840
关于HTTP的笔记
图解HTTP读书笔记
Web使用一种名为HTTP(HyperText Transfer Protocol,超文本传输协议)的协议作为规范,完成从客户端到服务器端等一系列运作流程。而协议是指规则的约定。可以说,Web是建立在HTTP协议上通信的。
Dreamy.TZK
2020/08/24
6060
图解HTTP读书笔记
面试官别再问我HTTP了
如果证书验证没问题,就从证书中取出服务器的公钥,然后使用它加密报文,向服务器发送以下信息:
shysh95
2021/11/16
3100
面试官别再问我HTTP了
连肝7个晚上,总结了计算机网络的知识点!(共66条)
http1.1中浏览器再也不用为每个请求重新发起TCP连接了,增加内容有:缓存相关首部的扩展,OPTIONS方法,Upgrade首部,Range请求,压缩和传输编码,管道化等。但还是满足不了现在的web发展需求,so,就有了http.2版本。
小灰
2020/07/15
7400
连肝7个晚上,总结了计算机网络的知识点!(共66条)
【HTTP】267- HTTP 的15个常见知识点复习
前言 自从入职新公司到现在,我们前端团队内部一直在做 ?每周一练 的知识复习计划,我之前整理了一个 [每周一练 之 数据结构与算法] (https://juejin.im/post/5ce2a20e6
pingan8787
2019/07/25
6190
【HTTP】267- HTTP 的15个常见知识点复习
终、《图解HTTP》读书笔记 - 汇总篇(总结)
又一本网络基础的书啃完了,这本书建议结合[《网络是怎么样连接的》读书笔记 - 汇总篇]这一篇读书笔记食用(当然也可以直接看原书)。
阿东
2022/08/13
1.3K0
终、《图解HTTP》读书笔记 - 汇总篇(总结)
原 图解HTTP
作者:汪娇娇 日期:2017年9月4日 公司发福利允许每个人买一本书,于是我就选了一本《图解HTTP》,好补补我的http基础常识,哈哈哈。不得不说,这本书真的是入门级书籍,非计算机的人也可以尝试读读
jojo
2018/05/03
1K0
原                                                                                图解HTTP
面试问你HTTP知识点?这篇搞懂秒杀90%知识点!
由于自身不带验证机制,任何人都可以上传文件,因此存在安全性问题,一般不使用该方法。
乔戈里
2019/07/10
1.1K0
面试问你HTTP知识点?这篇搞懂秒杀90%知识点!
(建议收藏)前端面试必问的十六条HTTP网络知识体系
URI, 全称为(Uniform Resource Identifier), 也就是统一资源标识符。它并不是我们常说的网址URL, 实际上URI = URN+URL。
若川
2021/12/10
7550
(建议收藏)前端面试必问的十六条HTTP网络知识体系
《图解HTTP》读书笔记
  目前国内讲解HTTP协议的书是在太少了,记忆中有两本被誉为经典的书《HTTP权威指南》与《TCP/IP详解,卷1》,但内容晦涩难懂,学习难度较大。其实,HTTP协议并不复杂,理解起来也不会花费太多学习成本,这本书的出现就及时缓解了该问题。对基础及核心部分的深入学习是成为一名专业技术人员的前提,以不变应万变才是立足之本。此外,这本书也是我的2016年度读书计划中的一本,它和《图解TCP/IP》一起作为计算机网络基础部分为我温故知新了一把,谢谢作者和译者,画了这么多图解让我们理解。
Edison Zhou
2018/08/20
8680
《图解HTTP》读书笔记
《图解 HTTP》 阅读摘要
这次做了一些笔记,方便自己和其他人翻阅和复习,因为这本书是 2014 年出的初版,所以有一些不怎么常用的技术,笔记中就省略了,只记一些比较常用的 ~
前端下午茶
2019/06/27
7450
深入了解HTTP(已完结)
在学习网络之前,了解它的历史能够帮助我明白为何它会发展为如今这个样子,能让我有探究它的兴趣。下面的这张图片就展示了“互联网”诞生至今的发展历程
yutingbai
2022/08/18
4090
深入了解HTTP(已完结)
图解HTTP
1.根据Web浏览器地址栏中指定的URL,Web浏览器从Web服务器获取文件资源(resource)等信息,从而显示出Web页面
硬核项目经理
2019/08/06
1.2K0
万字图解 | 深入揭秘HTTP工作原理
大家好,我是「云舒编程」,今天我们来聊聊计算机网络面试之-(应用层HTTP)工作原理。
公众号 云舒编程
2024/01/25
1.8K0
万字图解 | 深入揭秘HTTP工作原理
告别 HTTP
当时这篇有些地方没有解释到位,然后我周末抽时间把一些没解释清楚的地方重写了,而且还增加 HTTP 缓存技术 方面的面试题,新文章的内容相比以前多了 5000 + 字和 10 +张图。
小林coding
2022/05/21
5400
告别 HTTP
【计网】从HTTP/0.9 到 HTTP/3
为什么会出现 HTTP 协议,从 HTTP1.0 到 HTTP3 经历了什么?HTTPS 又是怎么回事?
JuneBao
2022/10/26
8400
【计网】从HTTP/0.9 到 HTTP/3
「查缺补漏」巩固你的HTTP知识体系
这次梳理的篇幅主要是涉及网络部分,包括HTTP等,对巩固自己的网络知识体系也是很有帮助的,进一步的对性能优化而言也是帮助很大的。
童欧巴
2020/12/31
6880
七、《图解HTTP》- HTTP首部和HTTP协作服务器
虽然平时感受不到,但是却是互联网天天在用的东西,这本书花了50多页的内容介绍它,可见它的重要性。
阿东
2022/08/12
2.1K0
七、《图解HTTP》- HTTP首部和HTTP协作服务器
相关推荐
HTTP协议简述
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档