静态资源
1、WebMvcAutoConfiguration原理
1.生效条件
在这个原理里找到自动配置类,ctrl+N
搜索WebMvcAutoConfiguration
。
如果接入了其它平台的设置,可以在
setting
中搜索keymap
,选择windows
后点击apply
恢复默认设置。
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)
@ImportRuntimeHints({WebResourcesRuntimeHints.class})
public class WebMvcAutoConfiguration {
-
第一条:
@AutoConfiguration
- 其中的
after
是指在{}
中的自动配置配置好后,自己再配。
@AutoConfiguration( after = {DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class} )
- 其中的
-
第二条:
@ConditionalOnWebApplication
,如果是web应用就生效。Conditional
可以当作判断的意思(生效条件)。type = Type.SERVLET
表示如果是serverlet
类型的web应用才生效。(如果是REACTIVE,则为响应式web)- 这的生效就是指后面的
public class WebMvcAutoConfiguration {
@ConditionalOnWebApplication( type = Type.SERVLET )
-
第三条:
@ConditionalOnClass
- 当系统中存在
{}
中的这些类才生效。 - 导入了springMVC,就有
DispatcherServlet.class
,WebMvcConfigurer.class
,导入了servlet,就有Servlet.class
@ConditionalOnClass( {Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class} )
- 当系统中存在
-
第四条:
@ConditionalOnMissingBean
- 容器中没有这个
been
才生效,WebMvcAutoConfiguration
才生效。 - 默认是没有的。
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
- 容器中没有这个
-
第五条:
@AutoConfigureOrder(-2147483638)
- 优先级
2.效果(生效后做了什么)
- 在
WebMvcAutoConfiguration
查找,发现有两个@Bean
,里面有两个Filter
HiddenHttpMethodFilter
:页面表单提交Rest请求(表单默认只有GET、POST
,如果添加了这个Filter,PUT、DELETE
也可以提交了)FormContentFilter
:表单内容Filter,这是配合上面HiddenHttpMethodFilter
的,默认情况下,只有GET(数据放URL后面)、POST(放请求体中)
可以携带数据,PUT、DELETE
的请求体数据会被忽略。这时加上FormContentFilter
就能不会忽略了。
- 继续往下看,可以看到又有一个
内部类
,叫WebMvcAutoConfigurationAdapter
,它实现了WebMvcConfigurer
(这个很重要)。- 给容器中放了
WebMvcConfigurer
组件,这个组件又给添加各种定制功能 - 比如参数解析器:controller上标的所有参数,都要由参数解析器来解析。
- 下图中从上往下分别是:
- 参数解析器
- 跨域
- 格式化器
- 拦截器
- 添加资源处理器(处理静态资源规则)
- 返回值处理器
- 视图控制器(/a直接跳转到 xxx.html 页面)
- 异步支持
- 内容协商
- 默认处理(默认接受:/)
- 配置异常解析器
- 消息转化器
- 路径匹配
- 视图解析
- 扩展:异常解析器
- 扩展:消息转换
- 给容器中放了
2、静态资源规则源码解析
静态资源规则源码,在WebMvcAutoConfiguration.class
下:
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
this.addResourceHandler(registry, this.mvcProperties.getWebjarsPathPattern(), "classpath:/META-INF/resources/webjars/");
this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (Consumer)((registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
registration.addResourceLocations(new Resource[]{resource});
}
}));
}
}
多分析一两个场景的自动配置,就可以熟练SpringBoot的一些用法了。
这个静态资源规则,将addResourceHandler
方法调用了两遍,添加了两种静态资源规则。
1.规则一:访问/webjars/**
,就去classpath:/META-INF/resources/webjars/
下找资源
第一种,有一个MVC静态路径(mvcProperties.getWebjarsPathPattern
)
this.addResourceHandler(registry, this.mvcProperties.getWebjarsPathPattern(), "classpath:/META-INF/resources/webjars/");
上面这条的意思是,Webjars的静态路径指向"classpath:/META-INF/resources/webjars/"
,访问Webjars,就会默认去指向的这个位置找资源。
ctrl+鼠标左键 点一下getWebjarsPathPattern
,进入后再 ctrl+鼠标左键 点击里面的webjarsPathPattern
,最后得到以下内容:
private String webjarsPathPattern = "/webjars/**";
可以得知访问/webjars/**
,就去classpath:/META-INF/resources/webjars/
下找资源。
2.规则二:访问/**
,就去静态资源默认的四个位置找资源
和前一条一样的操作依次点进getStaticPathPattern
、staticPathPattern
,可以得到以下内容(其实就在规则一的private String webjarsPathPattern = "/webjars/**";
上面):
private String staticPathPattern = "/**";
与规则一不同的是,这里点击后面resourceProperties
后面的getStaticLocations
,再点击,可以得到以下内容:
private static final String[] CLASSPATH_RESOURCE_LOCATIONS =
new String[]{
"classpath:/META-INF/resources/", "classpath:/resources/",
"classpath:/static/", "classpath:/public/"
};
可以得知静态资源默认的四个位置为:
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/"
只要将所有的静态资源放到以上四个文件夹中,项目就可以访问(没有可以自己创建,在resources
下创建)。
3.规则三:静态资源默认都有缓存规则的设置
静态资源的访问是通过addResourceHandler
来完成的,ctrl+鼠标左键第二个addResourceHandler
进入里面,可以看到三个catch,是缓存相关的规则。
registration.setCachePeriod(this.getSeconds(this.resourceProperties.getCache().getPeriod()));
registration.setCacheControl(this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl());
registration.setUseLastModified(this.resourceProperties.getCache().isUseLastModified());
如果浏览器访问了一个静态资源 index.js,如果服务器里这个资源没有发生改变,下次访问就可以直接让浏览器用自己缓存的东西,而不用给服务器发请求。
下依次说明这三个catch。
catchPeriod
:缓存周期,以s
为单位(getSeconds),每过多久就找服务器更新。依次点击getPeriod
、Period
发现没有设置默认值,那默认值就是0
。cacheControl
:HTTP缓存控制useLastModified
:是否使用最后一次修改。比如:- 浏览器在第一次访问服务器的一个静态资源后,又第二次访问这个资源,不是直接问服务器下载静态资源,而是先问最后一次的修改时间;
- 如果这个时间和自己第一次访问的修改时间一致,就不用下载资源了,直接使用自己缓存的资源就可以了;
- 若是修改时间不一致,就再发一次请求,下载该静态资源。
所有缓存的设置,直接通过配置文件
spring.web
点击resourceProperties
后,再点左边的Resources
,发现在WebProperties
下,而它的配置文件的设置在spring.web
下。
3.欢迎页规则
ctrl+n 搜索进入WebMvcAutoConfiguration.class
,找到以下内容:
在这里面找到WebMvcConfigurer
这个组件,在这里面配置了静态资源的规则。
EnableWebMvcConfiguration源码
再往下看可以看到EnableWebMvcConfiguration
组件,由其上面的@Configuration(proxyBeanMethods = false)
可以得知,这也是个配置类:
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({WebProperties.class})
public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {
}
SpringBoot
给容器中放了WebMvcConfigurationSupport
组件,如果我们自己放了WebMvcConfigurationSupport
组件,SpringBoot
放的就失效了。
点进
DelegatingWebMvcConfiguration
发现了WebMvcConfigurationSupport
,这个在前面分析WebMvcAutoConfiguration
源码时出现过,是@ConditionalOnMissingBean
(容器中没有这个been
才生效)的内容,但那时启动时进行的判断,现在这里已经启动了,所以这二者之间不存在冲突:
往下看,可以找到WelcomePageHandlerMapping
,而不管HandlerMapping
前面是什么,这些HandlerMapping
都有一个作用:根据请求路径/*
找那个handler
处理请求。
WelcomePageHandlerMapping
:访问静态资源路径下的所有请求,都在前面找到的四个静态资源路径下找,欢迎页也是一样(循着类一路点下去可以找到):
classpath:/META-INF/resources/
classpath:/resources/
classpath:/static/
classpath:/public/"
我们往下翻,可以发现一个方法
其中的for(String location : this.resourceProperties.getStaticLocations())
,意思就是遍历这些地方找location
,点进getIndexHtml
发现:
再往下看,里面有一个index.html
,这个就是欢迎页。
也就是说在四个静态资源路径下放一个index.html
,浏览器访问服务器就会默认访问这个index.html
。
Favicon
- 网站每次访问服务器时,都会在静态资源目录下寻找
Favicon
,找项目的静态资源库里有没有一个Favicon.ico
,这个就是网页图标。 - 这和SpringBoot没多大关系,和浏览器有关系。
4、自定义静态资源规则
自定义静态资源路径、自定义缓存规则
配置方式
怎么知道在配置文件中配什么,就能自定义一些静态资源的规则?
1.自定义webjars路径前缀
之前在分析WebMvcAutoConfiguration
的时候,往下翻,可以看到:
这个WebMvcConfigurer
之前提到过,非常重要,这个接口定义了SpringMVC底层所有的组件入口,如果要使用静态资源,在WebMvcConfigurer
中就有资源处理器的相关配置。
- 以分析静态资源为例,以后分析所有配置都是这样。以这个
WebMvcAutoConfigurationAdapter
为例,从它上面的@EnableConfigurationProperties({WebMvcProperties.class, WebProperties.class})
可以得知,它绑定了两个配置文件,分别为WebMvcProperties.class
,WebProperties.class
。 - ctrl+鼠标左键点进
WebMvcProperties.class
,得到以下内容,可以知道它绑定的是spring.mvc
的配置:
- ctrl+鼠标左键点进
WebProperties.class
,得到以下内容,可以知道它绑定的是spring.web
的配置:
- 所以,搞清楚这两个文件能配置的一些静态资源的规则就行了。
- 点进
spring.mvc
可以看到,有许多策略:
这些都不管,回到WebMvcAutoConfiguration
往下找静态资源这一部分功能,addResourceHandlers
:
点进getWebjarsPathPattern
(获得路径),再点进webjarsPathPattern
,发现它就在绑定了spring.mvc
的WebMvcProperties
下:
按照这个路径,我们可以知道,在配置文件application.properties
中,输入spring.mvc.webjars-path-pattern=/a/**
来修改配置。其中的/a
为自定义的静态资源文件夹,在配置文件中修改后,在浏览器内访问/a/**
(**为webjars的内容)就能得到webjars的内容。 - 自定义webjars路径前缀:
spring.mvc.webjars-path-pattern=/webjars/**
2.自定义静态资源访问路径前缀
- 同理,访问
getStaticPathPattern
可以得到静态资源访问路径前缀:spring.mvc.static-path-pattern=/**
3.自定义静态资源文件夹位置
- 这次点进
getStaticLocations
:
再点进staticLocations
,往上翻,发现是在spring.web
下:
所以,在application.properties
中,输入spring.web.resources.static-locations=
。
这的默认路径为:classpath:/META-INF/resources/, classpath:/resources/, classpath:/static/, classpath:/public/
,这些是浏览器可访问的静态资源的存放目录,想要自定义修改,就在spring.web.resources.static-locations=
后面输入想自定义的路径即可,修改后浏览器就可以在自定义的目录下找静态资源了。
在
spring.web.resources
里还定义了很多可自定义的配置,可以在application.properties
自定义。