前言:
我們都知道,SpringBoot啟動會默認加載很多xxxAutoConfiguration類(自動配置類)
其中SpringMVC的大都數功能都集中在WebMvcAutoConfiguration類中,根據條件ConditionalOnxxx注冊類物件;WebMvcAutoConfiguration滿足以下ConditionalOnxxx條件,類是生效的,并把其物件注冊到容器中,

那WebMvcAutoConfiguration生效給容器中配置了什么呢?
文章目錄
- WebMvcAutoConfigurationAdapter靜態內部類
- 一.組態檔前綴
- 二.只有一個有參構造器
- 三.原始碼分析addResourceHandlers方法
- 1.禁用掉靜態資源的路徑映射
- 2.原始碼分析webjars的底層規則
- 3.原始碼分析默認靜態資源路徑的底層規則
WebMvcAutoConfigurationAdapter靜態內部類
一.組態檔前綴
我們來看WebMvcAutoConfiguration類中的WebMvcAutoConfigurationAdapter靜態內部類:

這是一個配置類,組態檔的屬性和xxx進行了系結,
再看@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class, WebProperties.class})
我們來看當中的WebMvcProperties、ResourceProperties和WebProperties的位元組碼檔案
分別點進這三個類的位元組碼檔案中:



可以看到WebMvcProperties它是與組態檔前綴spring.mvc相關聯的,
ResourceProperties它是與組態檔前綴spring.resources相關聯,
WebProperties它是與組態檔前綴spring.web相關聯,
二.只有一個有參構造器
WebMvcAutoConfigurationAdapter靜態內部配置類只有一個有引數的構造器,那它會帶來什么特性呢?
它的有參構造器中所有引數的值都會從容器中確定
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();
}
我們來看下它的引數:
- 第一個引數是ResourceProperties resourceProperties 就是我們上面提到的@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class, WebProperties.class})中注冊開啟的第二個類,獲取和spring.resources系結的所有的值的物件
- 第二個引數是WebProperties webProperties 就是我們上面提到的@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class, WebProperties.class})中注冊開啟的第三個類,獲取和spring.web系結的所有的值的物件
- 第三個引數是WebMvcProperties mvcProperties 就是我們上面提到的@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class, WebProperties.class})中注冊開啟的第一個類,獲取和spring.mvc系結的所有的值的物件
- 第四個引數是ListableBeanFactory beanFactory ,這個是Spring的beanFactory,也就是我們的容器,
- 第五個引數是ObjectProvider messageConvertersProvider,找到所有的HttpMessageConverters
- 第六個引數是ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,找到資源處理器的自定義器
- 第七個引數是ObjectProvider dispatcherServletPath,相當與找dispatcherServlet能處理的路徑
- 第八個引數是ObjectProvider<ServletRegistrationBean<?>> servletRegistrations ,給應用注冊原生的Servlet、Filter等等
構造器初始化后,我們已經把所有的東西從容器中拿到了
三.原始碼分析addResourceHandlers方法
所有的資源處理默認規則都在addResourceHandlers方法中,如下:
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
if (!registry.hasMappingForPattern("/webjars/**")) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl).setUseLastModified(this.resourceProperties.getCache().isUseLastModified()));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl).setUseLastModified(this.resourceProperties.getCache().isUseLastModified()));
}
}
}
1.禁用掉靜態資源的路徑映射
我們打上斷點看它的默認規則是怎么起作用的,首先呼叫resourcePropertoes的isAddMappings()方法:

判斷this.resourcePropertoes的isAddMappings()方法是不是不為true,
- this.resourcePropertoes我們剛才在2中講構造器時講到的ResourceProperties resourceProperties 就是我們上面提到的@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class, WebProperties.class})中注冊開啟的第二個類,獲取和spring.resources系結的所有的值的物件
- isAddMappings()方法回傳的是this.addMappings的值,如下:

也就是說我們可以通過設定addMappings的值是false還是true來讓這個if陳述句是否執行
我們可以在組態檔中進行設定:

默認它是true,如果是false,那么他就進入if陳述句中,執行logger.debug("Default resource handling disabled");后結束該方法,else中的所有配置都不生效

else中的什么配置/webjars/**去哪找等等一些規則都不生效了,
也就是說我們通過設定add-mappings: false 來禁用掉了靜態資源的路徑映射,
禁用后所有的靜態資源都訪問不了了,
addMappings的值如果是true,那么他就不會進入if陳述句中,而是進入到else陳述句中,那么else陳述句的內容都得到了執行,下面我們看它是怎么配置靜態資規則的,
2.原始碼分析webjars的底層規則
進入到else陳述句中,第一行是Duration cachePeriod = this.resourceProperties.getCache().getPeriod();,它從resourceProperties里面獲取到關于快取的相關值,我們在yaml組態檔中配置一下這個值:

快取時間是以秒為單位的,如下:

意思就是我們所有的靜態資源默認可以快取存盤多少秒
我們debug接著往下走,看到cachePeriod中取到了剛剛yaml中設定的6666,以后我們的瀏覽器就會把我們的靜態資源快取6666秒:

debug接著往下走,我們到了注冊"/webjars/**"這個規則的地方:
if (!registry.hasMappingForPattern("/webjars/**")) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl).setUseLastModified(this.resourceProperties.getCache().isUseLastModified()));
}
也就是說我們訪問/webjars下面的所有請求都找我們的classpath:/META-INF/resources/webjars/路徑,其中還設定了其靜態資源的快取時間為6666秒,
拿jquery來舉例,為什么我們匯入jquery之后,我們只需要訪問/webjars/jquery/3.5.1/jquery.js就能夠訪問到/META-INF/resources/webjars/jquery/3.5.1/jquery.js,如下:


其快取時間也可以在瀏覽器中看到為6666秒:

3.原始碼分析默認靜態資源路徑的底層規則
我們在else里面接著往下debug,接著我們用mvcProperties屬性呼叫其getStaticPathPattern()方法

- this.mvcProperties我們剛才在2中講構造器時講到的WebMvcProperties mvcProperties 就是我們上面提到的@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class, WebProperties.class})中注冊開啟的第一個類,獲取和spring.mvc系結的所有的值的物件
- getStaticPathPattern()方法,這個方法回傳的是staticPathPattern的值,如下:

staticPathPattern的這個值可以在我們的組態檔中進行配置,它的默認值是/**,如下:

我們也可以把前綴配置成/resource/**,如下:

debug接著往下走,接下來呼叫的方法與上面的webjars是一樣的方法,只不過引數有所不同:

接下來我們具體看代碼:
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl).setUseLastModified(this.resourceProperties.getCache().isUseLastModified()));
}
把剛剛的前綴staticPathPattern得到后作為實參傳入hasMappingForPattern方法中,注冊前綴這個規則,剛剛我們在yaml中設定了前綴為/resource/**,也就是說我們訪問/resource/**下面的所有請求都找我們的this.resourceProperties.getStaticLocations() 路徑,其中也設定了其靜態資源的快取時間為6666秒,
this.resourceProperties.getStaticLocations()方法回傳的值是什么呢?我們點進去看一下:

this.resourceProperties.getStaticLocations()回傳的是this.staticLocations,這個staticLocations定義如下:

可以看到它是一個字串陣列,在無參構造器中進行了初始化,初始化的值是CLASSPATH_RESOURCE_LOCATIONS常量,常量的值為:
“classpath:/META-INF/resources/”, “classpath:/resources/”, “classpath:/static/”, "classpath:/public/“,這就解釋了靜態資源路徑為什么默認為這四個路徑,
看到這里你有沒有恍然大悟,如果文章對你有幫助就請點個贊收藏一下吧!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/248111.html
標籤:其他
