1. 程式人生 > 其它 >SpringBoot相關原理

SpringBoot相關原理

SpringBoot相關原理

靜態資源配置原理

SpringBoot啟動預設載入 很多xxxAutoConfiguration 類(自動配置類)。以SpringMVC功能的自動配置類 WebMvcAutoConfiguration為例。其使用註解@EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class })將屬性與配置類中的值進行繫結。處理資源的預設規則由addResourceHandlers()規定。若resources.addMappings=false會直接返回(禁用所有靜態資源的訪問)。之後會在Spring設定的預設的路徑("classpath:/META-INF/resources/","classpath:/resources/", "classpath:/static/", "classpath:/public/")下尋找靜態資源。

Rest原理(表單提交)

在我們沒有自定義HiddenHttpMethodFilter的時候會使用預設值進行處理。表單提交時再請求方式是POST的前提下使用_method=PUT/DELETE時。請求會被HiddenHttpMethodFilter攔截。判斷是POST請求之後獲取_method的值。原生的request會被包裝為requestWrapper,requestWrapper重寫了getMethod方法,返回的是_method對應的值。

請求對映原理

主要起作用的是DispatcherServlet中的doDispatch()方法。在獲取到請求之後getHandler()會根據請求找到合適的Handler(即Controller的方法)。Spring在啟動時掃描所有的Controller並解析註解,並把這些資訊儲存到HandlerMappings

中,其中RequestMappingHandlerMapping儲存了所有的@RequestMapping 和handler的對映規則。根據這些對映規則以及傳入的request最終確定使用哪個Controller方法

引數處理原理

首先在HandlerMapping中找到可以處理請求的Handler(即Controller的方法)。然後為當前的Handler尋找一個介面卡(HandlerAdapter)。之後會執行介面卡的handle()方法(mv = ha.handle(processedRequest, response, mappedHandler.getHandler());)。在這個方法中會獲得引數解析器argumentResolvers

。引數解析器會根據註解的型別來解析其對應的引數。SpringMVC能解析多少種方法引數,取決於有多少種引數解析器。在獲得引數解析器後,也會獲得返回值處理器returnValueHandlers,返回值處理器決定了能返回哪些引數。真正執行目標方法的函式是ServletInvocableHandlerMethod類中的Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);。確定目標方法每一個引數的值使用到了如下函式:Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);,首先獲取到方法引數的詳細資訊,通過增強for迴圈挨個判斷使用哪個引數解析器,如果匹配成功,就將解析器放入快取,以提高後續程式的執行效率。然後使用解析器進行解析得到引數對應的值。然後遍歷所有的方法引數獲得所有引數對應的值。

處理自定義引數的情況,例如自己封裝的類:

會在引數解析的過程中使用WebDataBinder將請求引數的值繫結到指定的JavaBean裡。因為使用HTTP協議傳輸的資料,傳輸的都是文字,而我們需要具體的包裝類,例如Integer,Date等等,WebDataBinder會利用裡面的Converters將請求資料轉化成指定的資料型別。再次封裝到JavaBean中。

如果傳輸的資料和自己封裝的類的屬性不是一一對應匹配的。可以通過重寫 WebMvcConfigurer中的addFormatters方法,再重寫addFormatters中的convert方法,自己按需將請求域中的資料封裝到自己的自定義類中。

內容協商原理

內容協商:根據客戶端接收能力不同,返回不同型別的資料。內容協商是在獲取了請求引數之後的事情。其需要將返回值進行處理,轉化為客戶端能夠接收的資料型別。

在拿到對應註解的處理器之後,在核心方法writeWithMessageConverters()中,首先獲取客戶端支援接收的內容型別(預設獲取Accept請求頭欄位的內容)。然後拿到能夠接收的型別和能夠提供的型別。使用雙重for迴圈進行匹配得到最佳匹配型別。然後再是一個for迴圈,在messageConverters中尋找支援最佳匹配型別的Convert,之後再使用這個Convert進行資料型別的轉換。

檢視解析原理

在處理的過程中,所有傳入的資料和檢視地址都會被放在ModelAndViewContainer中。在呼叫處理器方法執行完之後會返回一個ModelAndView物件。之後由processDispatchResult()方法決定頁面如何響應。在processDispatchResult()中由render()方法進行頁面渲染。render()方法通過檢視解析器解析檢視名稱得到View物件。View物件再呼叫自己的render()方法進行頁面渲染。

攔截器原理

根據當前請求,找到可以處理請求的handler以及handler的所有攔截器,並把攔截器放在HandlerExecutionChain中。然後為當前handler找一個介面卡(HandlerAdapter),在介面卡解析前執行applyPreHandle()。在該方法先順序執行所有攔截器的preHandle()方法,如果返回為True,執行下一個攔截器的preHandle(),如果返回為False,則倒序執行所有已經執行了的攔截器的afterCompletion()方法,並直接跳出,不執行目標方法。

所有的攔截器返回都為True,之後會執行目標方法。之後會倒序執行所有攔截器的postHandle()方法。在前面的步驟中有任何的異常,都會直接倒序執行afterCompletion()方法。

在頁面成功渲染完成之後,也會倒序執行afterCompletion()方法。

檔案上傳原理

檔案上傳解析器先使用isMultipart()先判斷是否為檔案上傳請求,之後使用resolveMultipart()對請求進行解析,並封裝為MultipartHttpServletRequest物件。之後尋找一個是介面卡(HandlerAdapter),再執行介面卡的handle()方法,在handle()方法中會使用引數解析器argumentResolvers中的RequestPartMethodArgumentResolver對屬於檔案型別的引數進行解析,將request中的檔案資訊封裝為一個Map,key是自己定義的名字,value是封裝好的MultipartFile。之後返回ModelAndView,之後再進行頁面渲染。

感覺自己總結的不太好,後續有時間會繼續完善,如有錯誤請指出