SpringBoot(⼗七)静态资源处理源码解析及配置
⽬录
SpringBoot版本:2.1.1
流程分析
先看下SpringBoot的MVC⾃动配置类WebMvcAutoConfiguration,位于spring-boot-autoconfigure-2.1.1.RELEASE.jar包下。
类上很多注解,⼀个⼀个解释,@Conditiona注解前⾯有说过,可以参考。
@Configuration:标注是⼀个配置类
@ConditionalOnWebApplication:应⽤类型为web应⽤时匹配
@ConditionalOnClass:当前类路径下存在Servlet.class,DispatcherServlet.class,WebMvcConfigurer.class时匹配
@ConditionalOnMissingBean:不存在WebMvcConfigurationSupport类型的bean时匹配
@AutoConfigureOrder:通过order可以对⾃动配置类进⾏排序,该类order为Integer.MIN_VALUE+10
@AutoConfigureAfter:在其他指定的⾃动配置类之后应⽤,这⾥是在
DispatcherServletAutoConfiguration,TaskExecutionAutoConfiguration,ValidationAutoConfiguration⾃动配置之后应⽤
注意上⾯标红的⼀⾏, 不存在WebMvcConfigurationSupport类型bean时匹配,即如果编写类继承了WebMvcConfigurationSupport,那么SpringBoot就不会应⽤该⾃动配置类,会出现什么情况呢?也就是下⾯要说的。
WebMvcAutoConfiguration关注两个静态的内部类WebMvcAutoConfigurationAdapter和EnableWebMvcConfiguration,EnableWebMvcConfiguration
先看下这个内部类,继承了DelegatingWebMvcConfiguration,上⾯的注释说配置等效于@EnableWe
bMvc,⾄于为啥,看下⾯的截图。暂时就不关注该类中的其他内容了,如RequestMappingHandlerMapping处理url映射....
DelegatingWebMvcConfiguration继承了WebMvcConfigurationSupport,该类也是⽤来配置MVC的类。
看DelegatingWebMvcConfiguration的这个⽅法,会⾃动装配WebMvcConfigurer类型的bean添加到configurers的属性delegates 中,⼀个List<WebMvcConfigurer>。该类的所有⽅法都是委托给了WebMvcConfigurerComposite,在WebMvcConfigurerComposite中是循环List调⽤对应⽅法,即将相关配置⽅法委托给了⾃动装配的WebMvcConfigurer类型的bean。下⾯截图列举⼀个为例。
这⾥传⼊的bean有两个,⼀个就是下⾯要说的WebMvcAutoConfigurationAdapter,另⼀个是我⾃⼰编写的配置类。
WebMvcAutoConfigurationAdapter
该类实现了WebMvcConfigurer接⼝和ResourceLoaderAware接⼝。
WebMvcConfigurer接⼝⽤来定制基于Java配置的SpringMVC,通过@EnableWebMvc启⽤。
这⾥主要关注的⽅法是重写后的addResourceHandlers()⽅法。什么时候调⽤呢?
在WebMvcConfigurationSupport中配置的Bean HandlerMapping被创建的时候就会调⽤addResourceHandlers()⽅法。该类中是⼀个空⽅法,那调⽤就是调⽤⼦类的⽅法,上⾯说了配置⽅法是委托给了⾃动装配的WebMvcConfigurer类型的bean,就包括WebMvcAutoConfigurationAdapter。
所以现在再来看这个⽅法。
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
//sources.add-mappings值为false,不执⾏操作,即禁⽤静态资源映射,默认为true,
if (!sourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
Duration cachePeriod = Cache().getPeriod();
CacheControl cacheControl = Cache()
.getCachecontrol().toHttpCacheControl();
/
/ 如果ResourceHandlerRegistry中不包含/webjars/**的路径映射
//则添加⼀个url匹配模式/webjars/**,资源位置在classpath:/META-INF/resources/webjars/
//就是/webjars/**这样的的url都会去classpath:/META-INF/resources/webjars/下资源
if (!registry.hasMappingForPattern("/webjars/**")) {
customizeResourceHandlerRegistration(registry
.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
.setCachePeriod(getSeconds(cachePeriod))
.setCacheControl(cacheControl));
}
//得到静态资源路径匹配模式,默认/**
String staticPathPattern = StaticPathPattern();
//如果ResourceHandlerRegistry中不包含/**
//这⾥逻辑跟上⾯就是⼀样了,不包含则添加⼀个url匹配模式,这是⽤于静态资源匹配的
//资源位置就是默认的静态资源位置,在org.springframework.boot.autoconfigure.web.ResourceProperties中定义 if (!registry.hasMappingForPattern(staticPathPattern)) {
customizeResourceHandlerRegistration(
404页面网站源码registry.addResourceHandler(staticPathPattern)
.addResourceLocations(getResourceLocations(
.setCachePeriod(getSeconds(cachePeriod))
.setCacheControl(cacheControl));
}
}
最后创建的完成的SimpleUrlHandlerMapping中的UrlMap(即静态资源url映射,url匹配对应的资源位置)如下所⽰,第三个/static/**是我⾃⼰添加的,资源位置为classpath:/hh/。
{/webjars/**=ResourceHttpRequestHandler ["classpath:/META-INF/resources/webjars/"],
/**=ResourceHttpRequestHandler ["classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/"],
/static/**=ResourceHttpRequestHandler ["classpath:/hh/"]}
这整个过程都是在容器刷新的⽅法finishBeanFactoryInitialization()中,实例化⾮懒加载bean的⽅法中完成的。
具体bean初始化过程详见AbstractAutowireCapableBeanFactory的doCreateBean()⽅法。
⾸先会在bean应⽤BeanPostProcessors之前实现⾃动装配带@Autowired注释的字段,setter⽅法,任意配置⽅法。
然后会在bean初始之前应⽤BeanPostProcessors的postProcessBeforeInitialization()⽅法,包括:
1、ApplicationContextAwareProcessor:回调Aware接⼝的⽅法
2、ServletContextAwareProcessor:同上
3、ConfigurationPropertiesBindingPostProcessor:扫描ConfigurationProperties注解,绑定bean属性
4、WebServerFactoryCustomizerBeanPostProcessor:将bean⼯⼚中的所有WebServerFactoryCustomizer bean应⽤到WebServerFactory bean。
5、ErrorPageRegistrarBeanPostProcessor:ErrorPageRegistry注册ErrorPages
6、InitDestroyAnnotationBeanPostProcessor:调⽤带注释的init和destroy⽅法,@PostConstruct、@PreDestroy,允许对Spring的Initializingbean和DisposableBean回调接⼝进⾏注释替代,注释可以应⽤于任何可见性的⽅
法,public,protected,private,可以注释多个,但建议每个⽅法只注释⼀个
初始化之后应⽤BeanPostProcessors的postProcessAfterInitialization()⽅法。
这⾥说的有点远了感觉= =||...
实践是检验真理的唯⼀标准
说了这么多,现在就来试试。
四个默认静态资源路径,分别是:
1. classpath:/META-INF/resources/
2. classpath:/resources/
3. classpath:/static/
4. classpath:/public/
这四个路径定义在org.springframework.boot.autoconfigure.web.ResourceProperties,在spring-boot-autoconfigure-
2.1.1.RELEASE.jar包下,其实很多默认配置都在这个包下⾯,有兴趣可以去看看。
准备⼯作
这四个⽬录默认是要我们⾃⼰建的,没有这四个⽬录的时候静态资源放到src/main/webapp下也是可以访问到的。
先在这四个地⽅新建⽬录,放上⼀个HTML⽂件,不做其余操作;
下⾯是我的项⽬⽬录,每个地⽅都放了⼀个HTML⽂件,等会直接⽤url访问,在META-INF/resources⽬录下建了⼀个img⽬录,放图⽚。
其中1.html⽂件的内容如下,其余的HTML⽂件内容只是标识⼀下是哪个⽬录下的⽂件:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论