springboot静态资源配置原理
springboot对静态资源的配置可参考WebMvcAutoConfiguration这个类,在spring-boot-autoconfigure.jar中
WebMvcAutoConfiguration
1 2 3 4 5 6 7 8 | @Configuration (proxyBeanMethods = false ) @ConditionalOnWebApplication (type = Type.SERVLET) @ConditionalOnClass ({ Servlet. class , DispatcherServlet. class , WebMvcConfigurer. class }) @ConditionalOnMissingBean (WebMvcConfigurationSupport. class ) @AutoConfigureOrder (Ordered.HIGHEST_PRECEDENCE + 10 ) @AutoConfigureAfter ({ DispatcherServletAutoConfiguration. class , TaskExecutionAutoConfiguration. class , ValidationAutoConfiguration. class }) public class WebMvcAutoConfiguration {<br> ....<br>} |
@Configuration(proxyBeanMethods = false):告诉容器这是一个配置类,且不代理bean方法,每次调用都会创建,这样容器启动时无需检查容器中是否已经存在
@ConditionalOnWebApplication(type = Type.SERVLET):判断当前webAplication的类型是否为servlet,如果是则继续执行
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }):判断必须存在指定的类才执行
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class):判断必须没有指定的类才执行
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10):控制执行顺序
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class }):在加载配置的类之后再加载当前类
WebMvcAutoConfigurationAdapter
在WebMvcAutoConfiguration这个类中,存在一个WebMvcAutoConfigurationAdapter 静态内部类,用于配置静态资源规则的。
1 2 3 4 5 6 7 8 9 10 11 | // Defined as a nested config to ensure WebMvcConfigurer is not read when not // on the classpath @Configuration (proxyBeanMethods = false ) @Import (EnableWebMvcConfiguration. class ) @EnableConfigurationProperties ({ WebMvcProperties. class , ResourceProperties. class }) @Order ( 0 ) public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer { .... } |
这个静态内部类中有且只有一个带参构造方法:
1 2 3 4 5 6 7 8 9 | public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider) { this .resourceProperties = resourceProperties; this .mvcProperties = mvcProperties; this .beanFactory = beanFactory; this .messageConvertersProvider = messageConvertersProvider; this .resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable(); } |
只有一个带参构造方法时,入参会从容器中进行查找。其中的 resourceProperties和mvcProperties是通过注解@EnableConfigurationProperties导入的,其中的XXXProperties又是通过指定前缀和配置文件进行绑定的;
WebMvcProperties
1 2 | @ConfigurationProperties (prefix = "spring.mvc" ) public class WebMvcProperties { |
ResourceProperties
1 2 3 4 5 | @ConfigurationProperties (prefix = "spring.resources" , ignoreUnknownFields = false ) public class ResourceProperties { private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/" , "classpath:/resources/" , "classpath:/static/" , "classpath:/public/" }; |
addResourceHandlers
在这个WebMvcAutoConfigurationAdapter 静态内部类中存在一个addResourceHandlers方法,这个方法就是用于静态资源规则配置使用的;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { //检查是否开启默认资源处理,默认是true,可以通过配置文件改为false,关闭所有的静态资源配置映射 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/**" )) { //对于webjars的访问全部映射到类路径下的/META-INF/resources/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)) { //对于配置的静态资源路径都会去this.resourceProperties.getStaticLocations()进行查找 customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern) .addResourceLocations(getResourceLocations( this .resourceProperties.getStaticLocations())) .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl)); } } |
this.resourceProperties.getStaticLocations():这个就对应到ResourceProperties类中的CLASSPATH_RESOURCE_LOCATIONS;
1 2 | private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/" , "classpath:/resources/" , "classpath:/static/" , "classpath:/public/" }; |
1 2 3 4 5 6 | spring: # mvc: # static -path-pattern: /res/** resources: add-mappings: false 禁用所有静态资源规则 |
欢迎页的处理
欢迎页使用的welcomePageHandlerMapping方法
1 | @Bean <em id= "__mceDel" > public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,<br> FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {<br> WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(<br> new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),<br> this .mvcProperties.getStaticPathPattern());<br> welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));<br> welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());<br> return welcomePageHandlerMapping;<br>}</em><br> |
HandlerMapping:处理器映射。保存了每一个Handler能处理哪些请求。
对于这个有参构造方法:
1 2 3 4 5 6 7 8 9 10 11 | WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders, ApplicationContext applicationContext, Optional<Resource> welcomePage, String staticPathPattern) { if (welcomePage.isPresent() && "/**" .equals(staticPathPattern)) { logger.info( "Adding welcome page: " + welcomePage.get()); setRootViewName( "forward:index.html" ); } else if (welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) { logger.info( "Adding welcome page template: index" ); setRootViewName( "index" ); } } |
可以看出判断条件,如果开启了欢迎页且静态路径必须匹配/**则会去index.html,要么是跳转到index的请求。
至此可以看出springboot对静态资源的所有默认规则。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?