springboot 静态资源访问原理
2021-09-02 本文已影响0人
Exception_Cui
SpringBoot 静态资源原理
SpringBoot启动默认加载 xxxAutoConfiguration 类(自动配置类)
SpringMVC功能的自动配置类 WebMvcAutoConfiguration
所以我们就可以分析WebMvcAutoConfiguration 这个类
WebMvcAutoConfiguration.java
@Configuration( //此类不被代理
proxyBeanMethods = false
)
@ConditionalOnWebApplication( //是不是一个web的应用, web应用就包含SERVLET
type = Type.SERVLET
)
//是不是包含 Servlet DispatcherServlet WebMvcConfigurer web应用本身就包含
@ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class})
//不包含 WebMvcConfigurationSupport 这个类
@ConditionalOnMissingBean({WebMvcConfigurationSupport.class})
@AutoConfigureOrder(-2147483638)
@AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class})
public class WebMvcAutoConfiguration {
...
public WebMvcAutoConfiguration() {
}
内部类 WebMvcAutoConfiguration ->WebMvcAutoConfigurationAdapter
@Configuration(
proxyBeanMethods = false
)
@Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class})
//关键
//EnableConfigurationProperties 开启绑定和 将绑定的类添加到容器
//WebMvcProperties == "spring.mvc"
//ResourceProperties =="spring.resources"
//WebProperties =="spring.web"
//此处就说明了 我们 配置文件 为什么可以生效
@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class, WebProperties.class})
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {
//springboot 底层的代码 如果类只有一个构造器
//那么 所有的构造器使用的类 都是在spring 的IOC容器里面获取的
public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebProperties webProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ObjectProvider<DispatcherServletPath> dispatcherServletPath, ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
this.resourceProperties = (Resources)(resourceProperties.hasBeenCustomized() ? resourceProperties : webProperties.getResources());
//此处就是将 一些我们如果配置的属性进行赋值
this.mvcProperties = mvcProperties;
this.beanFactory = beanFactory;
this.messageConvertersProvider = messageConvertersProvider;
this.resourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
this.dispatcherServletPath = dispatcherServletPath;
this.servletRegistrations = servletRegistrations;
this.mvcProperties.checkConfiguration();
}
}
@Bean
@ConditionalOnMissingBean //配置视图解析器,此处不是重点,如果我们配置了,就不用springboot的
public InternalResourceViewResolver defaultViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix(this.mvcProperties.getView().getPrefix());
resolver.setSuffix(this.mvcProperties.getView().getSuffix());
return resolver;
}
//静态资源加载原理
//重点
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// resourceProperties.isAddMappings 是不是默认禁用springboot 进行静态资源资源管理
/*
spring:
web:
resources:
add-mappings:true
默认值是true, 就是不禁用
*/
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
// 如果我们使用了webjars 这里就是说明 为什么 webjars 的静态资源可以访问
// 会在每个webjars jar包里面寻找/META-INF/resources/webjars/ 路径下的文件
//将他们 添加到spring boot 的静态资源
this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
/*
spring:
mvc:
static-path-pattern: /res/**
如果我们配置前缀, 所以资源路径就会编程 "/res/**"
*/
// this.mvcProperties.getStaticPathPattern() = "/**" 默认的静态资源路径规则
this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
/*
spring:
web:
resources:
static-locations: classpath:/haha/
如果我们配置了 静态资源路径,就会在我们配置的静态资源路径下面寻找
this.resourceProperties.getStaticLocations() 就成了 /haha/
*/
// this.resourceProperties.getStaticLocations() = {"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
//默认值,这里就说明了为什么springBoot的静态资源需要放到这几个文件夹下面
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
//如果使用原生的servlet,也将资源添加到原生的context下面
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
registration.addResourceLocations(new Resource[]{resource});
}
});
}
}
欢迎页处理规则 WebMvcAutoConfiguration.java
//HandlerMapping:处理器映射器。保存了每一个Handler能处理哪些请求。
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext,
//将/index.html 传入 //将前缀也传入
this.getWelcomePage(), this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(this.getCorsConfigurations());
return welcomePageHandlerMapping;
}
WelcomePageHandlerMapping.java
WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders, ApplicationContext applicationContext, Resource welcomePage, String staticPathPattern) {
//检测 welcomePage /index.html 是不是存在
//检测 前缀是否匹配
// 这里就说明了,如果我们使用了静态资源使用的前缀,就无法匹配的默认的欢迎页
if (welcomePage != null && "/**".equals(staticPathPattern)) {
logger.info("Adding welcome page: " + welcomePage);
//设置默认的欢迎页
this.setRootViewName("forward:index.html");
} else if (this.welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) { //这里是动态资源欢迎页,使用模板
logger.info("Adding welcome page template: index");
this.setRootViewName("index");
}
}
网站图标配置
这里是浏览器的功能,浏览器会自动请求访问/favicon.ico这个资源,如果存在浏览器就加上,和springboot 无关