【原始碼分析】 - SprignBoot是如何訪問工程目錄下的靜態資源?

Dkwestworld發表於2021-06-22

目錄

 

1、牛刀小試

1.1 圖片靜態資源的訪問

1.2 為靜態資源新增訪問字首

1.3  WelCome Page 的奇妙跳轉

2、那麼,SpringBoot是如何做到的呢?


​​​​​​​

1、牛刀小試

1.1 圖片靜態資源的訪問

先看官方怎麼說,點選連結,開啟 SpringBoot官方文件 

【原始碼分析】 - SprignBoot是如何訪問工程目錄下的靜態資源?

文件中明確指出:/static (or /public or /resources or /META-INF/resources) ,這幾個目錄是SpringBoot放置靜態資源的目錄,只要把靜態資源放到這幾個目錄下,就能直接訪問到。

新建 Spingboot web專案試下,新專案只有 /static 目錄 ,手動建立其他幾個靜態資原始檔夾,每個目錄新增1張圖片

【原始碼分析】 - SprignBoot是如何訪問工程目錄下的靜態資源?

啟動專案,分別訪問這四張圖片:

 

【原始碼分析】 - SprignBoot是如何訪問工程目錄下的靜態資源?

發現圖片均可訪問,

文件說的對,果然沒騙人,

由此我們認定 SpringBoot 訪問靜態資源 :當前專案根路徑 + / + 靜態資源名

 

1.2 為靜態資源新增訪問字首

By default, resources are mapped on /**, but you can tune that with the spring.mvc.static-path-pattern property. For instance, relocating all resources to /resources/** can be achieved as follows:

PropertiesYaml
spring.mvc.static-path-pattern=/resources/**
【原始碼分析】 - SprignBoot是如何訪問工程目錄下的靜態資源?

文件又解釋了一下,說,預設情況下SpringBoot是幫你對映的路徑是 /** ,

但是,如果你想加一個字首也可以,比如  /res/

技術圈有句話:先有業務才有技術,SpringBoot官方考慮到某些網站新增了登入驗證,一般需要登入後才能訪問專案中的資源,為了登入頁樣式也能正常顯示,方便放行靜態資源,直接給所有靜態資源新增一個字首,既可統一攔截,又可統一放開

操作:在配置檔案application.properties中新增

spring.mvc.static-path-pattern=/res/**
【原始碼分析】 - SprignBoot是如何訪問工程目錄下的靜態資源?

新增完再去訪問原來的dog圖片連結:http://localhost:8080/dog.jpeg

【原始碼分析】 - SprignBoot是如何訪問工程目錄下的靜態資源?

但是訪問:http://localhost:8080/res/dog.jpeg 發現這才可以

嘿嘿?

1.3  WelCome Page 的奇妙跳轉

7.1.6. Welcome Page
Spring Boot supports both static and templated welcome pages. It first looks for an index.html file in the configured static content locations. If one is not found, it then looks for an index template. If either is found, it is automatically used as the welcome page of the application.
【原始碼分析】 - SprignBoot是如何訪問工程目錄下的靜態資源?

文件說把一個名稱叫 index.html 的檔案放到任意的靜態目錄下,訪問 http://localhost:8080 即可到達,意思就是給你一個首頁跳轉的快捷方式(注意:需把1.2 的配置路徑去掉,否則會導致welcome page功能失效,後面原始碼分析會說到)

新建html,放到  /static 下,訪問:

【原始碼分析】 - SprignBoot是如何訪問工程目錄下的靜態資源?

2、那麼,SpringBoot是如何做到的呢?

 

接下來看原始碼探究 SpringBoot 靜態資源配置原理    》》》》  gogogo

原始碼位置在:spring-boot-autoconfigure-2.5.1.jar  這個jar裡面,具體的目錄如下:

/spring-boot-autoconfigure-2.5.1.jar!/org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration.class
【原始碼分析】 - SprignBoot是如何訪問工程目錄下的靜態資源?

WebMvcAutoConfiguration 類裡面找到 addResourceHandlers 方法,顧名思義 新增資源處理器

        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            // 相當於一個開關去控制靜態資源處理器的載入,預設為true,設定為false就會禁止所有規則
            if (!this.resourceProperties.isAddMappings()) {
                logger.debug("Default resource handling disabled");
                return;
            }
            //第一個就配置webjars的訪問規則,規定在類路徑的/META-INF/resources/webjars/路徑下,感興趣的同學可以點進方法去,裡面還配置了webjars的瀏覽器端快取時間,是在application。propertities中的一個配置項 spring.web.resources.cache.period  
            addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
            //這裡配置了靜態資源的四個訪問路徑
            addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
                registration.addResourceLocations(this.resourceProperties.getStaticLocations());
                if (this.servletContext != null) {
                    ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);
                    registration.addResourceLocations(resource);
                }
            });
        }

 

【原始碼分析】 - SprignBoot是如何訪問工程目錄下的靜態資源?

第一個if判斷 this.resourceProperties.isAddMappings()  去配置檔案獲取

spring.resources 這個屬性,預設是 true , 如果設定為false 那麼就等於禁用掉所有的靜態資源對映功能,不行就試一下
#springapplication.propertities中配置
spring.web.resources.add-mappings=false
【原始碼分析】 - SprignBoot是如何訪問工程目錄下的靜態資源?

重啟專案,發現首頁無法訪問了...

【原始碼分析】 - SprignBoot是如何訪問工程目錄下的靜態資源?

改回 true ,首頁就又可以訪問了

不要停留,繼續看第二個 addResourceHandler 方法,打斷點看看這個方法新增了什麼規則 

【原始碼分析】 - SprignBoot是如何訪問工程目錄下的靜態資源?

沒錯,第二個addResourceHandler 方法就表明  / ** 下的所有請求,都在這四個預設的位置去找靜態資源對映 ,這四個目錄在官方文件中提到過。

另外,訪問路徑字首是在 this.mvcProperties.getStaticPathPattern() 獲取的,配置上:

spring.mvc.static-path-pattern=/res/**

打斷點如下:

【原始碼分析】 - SprignBoot是如何訪問工程目錄下的靜態資源?

注意?:  所有的請求先去controller控制器找對映,找不到,再來靜態資源對映器。

到這裡解決了靜態資源目錄的問題。

馬不停蹄,探究  Welcome Page 的事情 》》》》》

還是在 WebMvcAutoConfiguration 這個類:搜尋  “WelcomePage” :

@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, Resource welcomePage, String staticPathPattern) {
        if (welcomePage != null && "/**".equals(staticPathPattern)) {
            logger.info("Adding welcome page: " + welcomePage);
            setRootViewName("forward:index.html");
        }
        else if (welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) {
            logger.info("Adding welcome page template: index");
            setRootViewName("index");
        }
    }
【原始碼分析】 - SprignBoot是如何訪問工程目錄下的靜態資源?

根據有參構造可以看出來,只有 歡迎頁這個資源存在,並且 靜態資源訪問路徑是 /** ,才能重定向到indes.html ,否則就會去找 Controller 處理。

這就解釋了,上面為什麼配置了靜態資源訪問路徑 為/res/** 後導致首頁無法訪問到 的問題

好了,前面牛刀小試的坑已經填完了,關於SpringBoot 靜態資源配置原理 這篇總結就到這了

相關文章