SpringBoot静态资源加载原理
之前的文章,我们说过,SpringBoot启动时会默认加载各种xxxAutoConfiguration 类,即自动配置类。
- 静态资源的加载原理
SpringMVC功能的可以查看源码的 WebMvcAutoConfiguration类。
@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 {
从源码中,我们可以看出在满足
- @ConditionalOnWebApplication(type = Type.SERVLET) 是webapp
- @ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })容器中有Servlet、DispatcherServlet、WebMvcConfigurer 三个类
- @ConditionalOnMissingBean(WebMvcConfigurationSupport.class) 容器中没有WebMvcConfigurationSupport 类
满足以上条件时,该配置类会生效
其中该类中一个重要的内部配置类是静态资源加载原理的核心
@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {
其中 @EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class })将该类和WebMvcProperties与ResourceProperties关联的配置文件相关联,我们可以查看这两个类的源码
@ConfigurationProperties(prefix = "spring.mvc")
public class WebMvcProperties {
@ConfigurationProperties(prefix = "spring.resources", ignoreUnknownFields = false)
public class ResourceProperties {
此时我们可以看出WebMvcProperties类与配置文件中以spring.mvc为前缀的配置相关联,而ResourceProperties类则与配置文件中以spring.resources为签注爹配置相关联
我们知道spring.resources.static-locations 是配置spring静态资源目录的一个配置属性。这时候我们就可以去查看ResourceProperties类的源码
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/" };
/**
* Locations of static resources. Defaults to classpath:[/META-INF/resources/,
* /resources/, /static/, /public/].
*/
private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
这里就体现了spring默认配置的静态资源路径是"classpath:/META-INF/resources/",
“classpath:/resources/”, “classpath:/static/”, “classpath:/public/”
我们可以直接将静态资源文件放在这几个目录中,就可以直接访问。
- WebMvcAutoConfigurationAdapter
该类是spring静态资源默认加载的一个重要配置类,该类又一个构造方法
public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties,
ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider,
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,
ObjectProvider<DispatcherServletPath> dispatcherServletPath,
ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
this.resourceProperties = resourceProperties;
this.mvcProperties = mvcProperties;
this.beanFactory = beanFactory;
this.messageConvertersProvider = messageConvertersProvider;
this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
this.dispatcherServletPath = dispatcherServletPath;
this.servletRegistrations = servletRegistrations;
}
该构造函数所有参数的值都会从容器中确定
ResourceProperties resourceProperties 获取和spring.resources绑定的所有的值的对象【ResourceProperties.class】
WebMvcProperties mvcProperties 获取和spring.mvc绑定的所有的值的对象【WebMvcProperties.class】
ListableBeanFactory beanFactory 是Spring的beanFactory
HttpMessageConverters 找到所有的HttpMessageConverters
ResourceHandlerRegistrationCustomizer 找到 资源处理器的自定义器
…
有时我们会添加spring.mvc.static-path-pattern属性来给访问路径添加前缀
首先我们看到他是spring.mvc开头的属性,所以与WebMvcProperties类有关
private String staticPathPattern = "/**";
我们在这个类中果然找到了该配置项默认的路径
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
...
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
.addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
.setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
}
}
而他又在WebMvcAutoConfigurationAdapter中的addResourceHandlers方法进行判断
- 欢迎页的处理规则
我们将名为index.html的文件放在默认静态资源目录下,在项目启动后则会默认访问欢迎页,该配置依旧在WebMvcAutoConfiguration类中可以找到相关配置
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
return welcomePageHandlerMapping;
}
其中的welcomePageHandlerMapping是该配置的核心。
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");
}
}
这块代码的可读性很强
当if (welcomePage.isPresent() && “/**”.equals(staticPathPattern)) {该条件成立时,即可转发请求至index.html 即欢迎页存在且staticPathPattern为 “/**”
其中staticPathPattern在上面我们说过,是一个配置项,与WebMvcProperties类相关联
以上就是关于SpringBoot静态资源加载的相关原理。
其主要代码旧在WebMvcAutoConfiguration类中,该类也是SpringMVC的重要自动配置类