成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java進階篇——Springboot2源碼探究

開發 前端
看起來是將元數據中的包名提取成數組,我們打開看看該類在初始化的時候具體干了什么,可以看到實際上在初始化時調用了一個ClassUtils.getPackageName, 傳入了一個什么呢,metadata.getclassname,他是什么呢,打斷點!

1.@EnableAutoConfiguration

除了元注解之外,EnableAutoConfiguration包含了兩大重要部分:

1)@AutoConfigurationPackage注解

該注解只導入了一個內部類:AutoConfigurationPackages.Registrar.class

類中有兩個方法

從名字上看,registerBeanDefinitions方法注冊了定義好的一些Bean,determineImports方法決定這些要不要導入

registerBeanDefinitions調用了register方法,并傳入了registry參數和一個元數據名字數組。registry參數是一個接口,
實際場景中必然是使用的實現類,可以在該方法打斷點debug

發現實際上他的實現類是一個名為DefaultListableBeanFactory,并且可以清晰的看到該類的一些基本屬性的值

可以看到,registry中存儲的是一些關于項目程序的基本配置和bean實例名。比如一些網頁支持組件和springContext以及一些加載器

還有用戶自定義的類,這些類組件中存儲了bean名字、作用域、懶加載等等

再來看另一個參數:new PackageImports(metadata).getPackageNames().toArray(new String[0])

看起來是將元數據中的包名提取成數組,我們打開看看該類在初始化的時候具體干了什么,可以看到實際上在初始化時調用了一個ClassUtils.getPackageName,
傳入了一個什么呢,metadata.getclassname,他是什么呢,打斷點!

,實際上就是啟動類的全名,com.***.application,而這個方法則是將classname的前綴提取出來,即提取出我們的包名com.&&&

即這個AutoConfigurationPackages.register方法傳入了我們的一大堆初始bean的名字、配置和總包名com.**,我們研究研究他做了什么

首先是判斷定義的bean中有沒有Bean,這個bean是類的屬性,存著當前類的全名:org.springframework.boot.autoconfigure.AutoConfigurationPackages

大概想處理的是用戶自定義了AutoConfigurationPackages類的情況。當前是沒有定義的,所以直接走else邏輯

new了一個GenericBeanDefinition,暫且叫他通用的bean定義工具,set一大堆東西。之后調用了注冊方法。把工具丟了進去。

這個注冊方法里大概是將AutoConfigurationPackages類同樣注冊進了定義bean的map中,然后將map中的所有值加入到了這個默認的bean工廠中,之后這個類就走完了。

因此該注解的作用即是將自定義的bean以及一些基本類型、原始組件注冊到bean工廠中

2)AutoConfigurationImportSelector類

該類中點進去映入眼簾的就是selectImports方法。聽起來名字是選擇導入,也就是該方法決定了要加載什么依賴組件

而該方法調用了并且只調用了getAutoConfigurationEntry方法來獲取要加載的組件。

我們來看看這個方法,先是調用getAttributes獲取了某個東西,打斷點發現是

這樣就很熟悉了,是EnableAutoConfiguration注解的兩個屬性值,雖然默認值為null。點進方法體發現確實是這樣。

getCandidateConfigurations(annotationMetadata, attributes)方法調用了一大串,最終調用了這個方法loadSpringFactories,
該方法的大致內容是,從當前所有的依賴包中加載META-INF/目錄下的spring.factories文件中尋找一些組件。
可以看到他先嘗試從緩存中拿,如果為空,則去依賴包中的META-INF/目錄下的spring.factories中加載。

拿到這個組件列表之后,還要進行一層過濾,抽取含有factoryTypeName的組件列表。
這個name即是org.springframework.boot.autoconfigure.EnableAutoConfiguration自動配置注解

再回到getEntry方法,之后對獲取到的組件列表進行去重,然后試圖從列表中拿出排除項,
也就是attributes中獲取到的EnableAutoConfiguration注解的兩個屬性值的內容。很容易理解,屬性值中配置了要排除的內容將在這里進行排除。

而后調用filter方法對列表進行篩選,而篩選使用的是autoConfigurationMetadata這個類,
由此可見,這個類是某種篩選規則,它里面存儲了501個properties,所以篩選規則可能就是逐一比對,篩選出Metadata中有的組件。

篩選出來的結果即是最終要加載的組件bean。

也就是說,@EnableAutoConfiguration的兩個重要成員,一個決定了要加載默認的哪些組件(用戶自定義bean、數值包裝類、字符串類等等)
和配置,另一個決定了要加載哪些外部依賴類,即通過starter等通過pom引入的組件。

2.請求處理

如何知道spring是怎么、在哪處理請求的呢,有個很簡單的方法,在properties中將日志級別設置為debug,即dubug=true。而后運行程序,發送任意一個請求

就會發現spring打印出了關于處理該請求的一些細節,比如處理請求是從初始化DispatcherServlet開始的,
由此可見請求處理最重要的便是DispatcherServlet。而后AbstractHandlerMapping識別到了處理該請求的具體方法。

我們進入到DispatcherServlet中,查看他的方法。

學過mvc原生web開發的都知道,servlet有兩大重要方法,doGet和doPost。而DispatcherServlet繼承了FrameworkServlet繼承了HttpServletBean,
HttpServletBean繼承了HttpServlet,由此可知,DispatcherServlet也是一個httpServlet。那么我們就有思路了,從他的do**方法開始探究。

1)doDispatch

從名字看,這個方法似乎是為了做轉發。并且他的參數幾乎和doGet方法是一模一樣的

最開始是初始化了一大堆東西,包括處理異步請求的異步管理器以及檢查是否是文件上傳的請求巴拉巴拉,而后這個getHandler方法,直接獲取到了處理這個請求的具體方法。

它是如何處理的呢,他遍歷了一個handlerMappings的集合,這個mapping里面存儲的是spring一些專處理映射的類

,比如歡迎頁的映射,以及我們使用requestMapping標注的url。這樣就打通了,他會在requestMappingHandlerMapping中查找到/hello請求并且找到他映射的方法。
具體查找調用了HandlerMapping的gethandler,由此就和日志中的對上了,gethandler方法中就是根據url在映射中找方法,先拋開這個細節不看。

拿到這個處理器(方法)后,將其丟入到了HandlerAdapter請求適配器中,這個在mvc架構中熟悉的身影。
之后并不是立即執行該方法而是先判斷方法的種類,如果是get或者head方法,則執行邏輯。

這個邏輯會衡返回一個-1,也就是寫死的,我不理解為什么是這樣,在網上搜了Last-Modified,發現這是一種緩存機制,
這也就理解了為什么必須是get方法,而他實現需要實現LastModified接口,我并沒有實現這個,所以spring這個判斷邏輯會衡false。

之后是一個applyPreHandle的方法,點進去就會發現是使用當前spring的攔截器組件對請求進行攔截,

能發現就是一些請求方法攔截器、token攔截器、資源攔截器等等,也就是一些壞的請求會在這條被攔截

之后就是請求適配器執行自己的處理邏輯了,可以看到他返回的是一個modelAndView類型的實例,那么就意味著,此時方法已經被執行了。

但是實際上并沒有使用modelAndView作為返回值,而是直接返回的string。所以mv是一個空值,但是可以在響應體中觀察到,
已經有19字節的東西被寫進了響應體中,頁印證了方法已經被執行。

緊接著是判斷請求是否是異步請求,如果是異步請求可能會做First響應之類的處理。

再往下是一個名叫應用默認的視圖名的方法,將請求體中或者默認的視圖名加入model中。

因為如果應用了modelandview,此時才只是一個model,必然要添加對應的view??梢院唵螠y試一下。我們在處理方法中new一個modelandview對象,設置一個model值并返回。

可以看到,經過此方法之后,我們并沒有設置view值,系統默認將hello當作了view加入model,這個默認值即是請求路徑去掉前面的/。

這個方法之后,又是一個類似于攔截器,有點類似于在方法執行前后各執行一次攔截。攔截器執行完畢后,方法結束。
后面就是一些兜底處理,比如如果是文件相關之類的請求,要關閉對應的流。如果是異步請求執行怎樣的邏輯。

2)handle方法

我們知道,適配器的handle方法里面執行了方法邏輯,具體是怎么執行的呢。實際上是調用了super的AbstractHandlerMethodAdapter的handle方法。
這個handle方法又會調用自己(RequestMappingHandlerAdapter)的handleInternal方法。該方法內對session做了一些處理,
而后調用invokeHandlerMethod方法,這個方法內做了很多的處理。比如WebDataBinderFactory binderFactory對象,他是對參數之中的數據格式做轉換的,他里面初始化了128種對象轉換的方式;

又或者初始化一些參數解析器和返回值處理器:里面對各種參數和返回值做對應的解析和處理,總之就是把這些丟入到一個mavContainer容器中。

然后調用invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0])方法,同時傳入的還有webRequest,
這個就是將請求體和響應體包裝到了一起。這個方法里面第一行就直接執行了方法,可以看到此時已經有返回值了。

這個方法就比較簡單了:獲取參數、執行方法

①getMethodArgumentValues

該方法最開始是獲取映射方法的參數類型以及參數名

之后做的事大概可以猜到,就是從請求中找出這些參數名對應的參數并且轉化成對應的類型。可以看看具體的

首先定義了一個接收數組,用來存儲獲取到的參數,而后嘗試從providedArgs中拿對應的參數,但實際上這個參數傳的是空值。

所以執行后面的邏輯,從請求中拿,并且同時傳入了mav容器,這個容器中就有格式轉換器和返回值處理器等。

該方法里面有兩個重要的構成,getArgumentResolver獲取參數解析器和resolveArgument解析參數。獲取參數解析器方法中,
循環目前已經存進ioc容器的解析器組件,和參數進行一一比對,找到可以解析對應參數的解析器。

解析參數方法中,就是獲取參數名容器→獲取方法參數容器→獲取參數名→解析參數。之后會做很多的后續處理,比如格式轉換之類的。

②doInvoke

這個方法比較簡單,利用之前已經存入InvocableHandlerMethod中的反射方法public java.lang.String
com.glodon.controller.HelloController.home(java.lang.String),實際上,該對象實例也是專門存儲方法處理的相關組件的。
獲取到方法后,利用spring反射機制執行該方法。

3)請求響應

前面將方法執行完之后,封裝完modelAndView,在執行完處理后攔截器后,還要執行一個兜底方法對結果進行處理,從名字來看,他是用來處理結果轉發的。

開始是判斷方法執行是否有異常,如果有則走異常處理邏輯。而后如果modelandview不為空,則執行一個render方法render(mv, request, response)

render方法首先從請求中拿到語言標識,并加入到響應體中,而后拿出modelandview中的視圖名,即重定向或者其他視圖。
然后調用resolveViewName方法對視圖名進行處理,對當前容器中的所有解析器進行遍歷,哪個可以解析這個視圖名,就直接返回解析結果。

解析器的解析過程,以ContentNegotiatingViewResolver舉例。

這個解析器獲取了請求的Attributes,然后傳入getMediaTypes方法中并調用來獲取返回數據類型。

getMediaTypes里面其實就是一個雙重循環匹配,格式化網頁請求→獲取瀏覽器請求頭中的可接受媒體類型→獲取系統可生產的媒體類型→初始化匹配的媒體類型。
然后進行一個雙重循環,如果匹配成功,則把對應的媒體類型加入到compatibleMediaTypes中。

排序完成后就是一個set→List,然后進行一個排序,排序的依據就是媒體類型的權重。

瀏覽器在發送請求的時候會給服務器一個accept,里面明確表示了瀏覽器可以接收的返回類型以及他的權重,而這里的排序就是按照這個權重進行排序的。

該方法返回后,在接著看解析方法,之后調用了getCandidateViews獲取候選視圖。

getCandidateViews方法內同樣是個雙層循環。外層是除了當前解析器外的其他三個視圖解析器,內層是對匹配到的媒體類型。

通過調試,發現最終是被InternalResourceViewResolver成功處理,我們只看他的細節。

同樣還是resolveViewname方法,該方法先嘗試去緩存中拿,拿不到了才執行createView方法創建視圖。而這個方法就很清晰明了了

判斷是重定向還是轉發來生成對應的視圖。最終返回合適的視圖,添加緩存巴拉巴拉。

我們測試的剛好是一個重定向視圖,所以返回的結果就是bean為redirect,url為/helloWorld的視圖。?

責任編輯:武曉燕 來源: 今日頭條
相關推薦

2022-09-13 09:02:19

SpringBootStarter機制

2017-09-19 15:01:06

PHP漏洞滲透測試

2023-03-26 09:08:36

2024-05-08 08:59:02

2015-10-20 15:57:48

ReactiveCociOS

2023-07-10 07:22:16

2021-01-01 09:20:20

操作DjangoORM

2023-08-29 10:27:32

2011-10-24 09:49:37

管理非限制進程SELinux

2017-09-19 15:45:39

2010-07-05 13:08:42

用Visio畫UML圖

2021-10-27 16:52:37

LayoutInfl源碼解析

2021-09-12 07:30:10

配置

2021-05-17 09:50:06

Kubebuilde源碼CURD

2021-04-26 09:25:10

JavaKafka架構

2022-10-27 10:32:09

Presto SQLJoin大數據

2017-09-12 10:26:47

springbootmaven結構

2021-01-19 15:59:14

程序員算法

2021-05-17 05:51:31

KubeBuilderOperator測試

2021-10-27 09:59:35

存儲
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 免费中文字幕 | 不卡一区二区三区四区 | 精品一区av | 久久久无码精品亚洲日韩按摩 | 嫩草国产 | 亚洲日韩欧美一区二区在线 | 国产极品粉嫩美女呻吟在线看人 | 毛片网站在线观看视频 | 欧美日韩三级 | 国产日韩91 | 日韩免费福利视频 | 操视频网站| 欧美日韩一区二区在线观看 | 伊人热久久 | 久久久久久久久毛片 | 免费在线a视频 | 亚洲看片网站 | 在线激情视频 | 亚洲女人天堂网 | 国产婷婷 | 91影视| 美女露尿口视频 | 欧美精品被 | 国产亚洲一区二区三区在线观看 | 久久久国产精品网站 | 91精品国产91久久久久久吃药 | 免费在线播放黄色 | 亚洲精品自拍 | 久久99精品久久久久久秒播九色 | 日韩在线成人 | 亚洲在线免费 | 三级黄色网址 | 嫩草黄色影院 | 国产精品成人一区二区三区 | 中文字幕一区二区三区在线视频 | 国产精品久久久久无码av | 在线观看 亚洲 | 国产伦精品一区二区三区高清 | 中文字幕欧美一区 | 亚洲人a| 日韩在线免费视频 |