記一次閱讀mybatis--spring 源碼出現的使用 @postConstruct 不生效引出的血淚!(--jdk版本)

.案發場景及動機描述:

在這裏插入圖片描述
1.本來是在學習mabtis如何集成到spring的源碼的 MapperFactoryBean中他的 所代理的 mapperInterface 接口上面方法註解信息如 :@Select*from biao ,解析到底是如何被sprinig 在哪裏所被完成的

--> 即spring所提供的一個bean實例後在執行init裏面時提供了幾個擴展點 --> **InitializingBean 接口**,
其能在bean執行 -->**initializeBean -->invokeInitMethods(之前和之後會執行後置處理器們)
 -->((InitializingBean) bean).afterPropertiesSet();**--(到這裏我把此步記爲A)

備註:mybatis所繼承的那個後置處理器生效是在執行invokeInitMethods 過程,它的前面 所有的後置處理器們會執行自身的beforePostProcessorxxxxx 方法,而其中的 @PostConstruct的生效就是在此before中通過一個叫 commonAnnotationPostProcessor的一個spring內置的後置處理器生效的後面有其調用鏈。

–> 對於mybatis 到這裏就會 由於MapperFactoryBean 這個工廠bean不僅實現了 FactoryBean 接口,還繼承了 -->SqlSessionDaoSupport-->它又繼承了DaoSupport--> 它繼承了 InitializingBean,即MapperFactoryBean 即相當於是實現了spring的其中一個實現接口InitializingBean的擴展其在執行到A後,`

就會調用到其父類DaoSupport中 方法afterPropertiesSet()-->再調用自己的 checkDaoConfig()
-->這裏面就會完成剛開頭所說的xxxx解析xxx`

2.而此時自己回想起了@postConstrct 的註解也是再init階段大概,於是再gradle所編譯的spring5.0源碼中想簡單看看起調用原理 --> 結果發現死活這裏都無法執行到,換了n種方式,

3.後面我又在另一個非源碼的普通spring項目種測試,發現卻執行到了。
好嘛,既然它被執行到了,那我就先看此@postConstrcut 到底如何被能夠執行到吧(實在無法直接解決了,就只好先弄清楚原理後,在來想思考爲啥它在我的源碼種執行不到)

二. @postConstrct 的調用鏈

在這裏插入圖片描述
簡而言之,我的spring5.0源碼中debug到獲取 getBeanPostProcessors 準備調用 後置處理器的執行鏈時,居然沒有這個 關鍵 的 commonAnnotationBeanPostProcessor !!, 其實這裏就應該自己產生懷疑了,因爲我自己看spring所編譯的源碼項目時,所有源碼都過完了的,都始終沒有在bdMap 或是 其list中有看到過commonAnnotationBeanPostProcessor 。
(@postConstruct 所標註的方法就是通過它才能夠被執行調用的!!!內部是通過它的父類InitDestroyAnnotationBeanPostProcessor 中執行反射執行xxx)

三. 確定bug的表面原因了:是我的源碼中 無spring內部所應該註冊上的一個後置處理器:commonAnnotationBeanPostProcessor

四. 分析此spring提供的後置處理器 commonAnnotationBeanPostProcessor

1.spirng內置後置處理器應該大多數是在 this() -->構造全局的Reader中,具體加入時機如下:
在這裏插入圖片描述
2.既然都已經找到了此後置處理器應該在上面的時刻裏給註冊到工廠的,那麼spring源碼沒有此後置處理器的原因肯定就是上面的if 判斷條件沒有通過了,即 jsr250Present == false;
在這裏插入圖片描述
其實通過查看此 布爾屬性 jsr250Present 的獲取,大概可以判斷:檢測是否能正常加載到類名文件“javax.annotation.Resource”–> 此文件其實就是javax擴展包中的,具體如下:
在這裏插入圖片描述
我的源碼項目中沒有獲取註冊成功 commonAnnotationBeanPostProcessor 的原因其實從這裏就大致可以判斷出,我的spring5.0源碼肯定是類加載此 Resource 文件沒加載到,出錯了,–> 那麼問題來了,憑啥我的源碼項目會有可能居然加載不到此 Resource 類呢???
其實到這裏我是非常想不通的,沒辦法,只有兩個對比看到底兩個項目中 所指向到那加載 Resource這個類時,他們各自都是什麼樣的狀態的!!

五. 對比兩個項目中 jsr250Present 所獲取的過程(即判斷類加載Resource的異同)

在這裏插入圖片描述
上面是jsr250Present 的值獲取的調用鏈,可以明確看到,就是在loadClass(“xxxxresouce”),
如果類加載器加載不到出異常,就會返回false, 能就是 true;

–> 類加載不到的原因產生:經過我仔細的對比,發現兩個項目的到此處的類加載器居然不一樣,具體如下:

在這裏插入圖片描述
到這裏,其實我都是不敢相信的,爲何他們的對應的類加載器是居然不一樣的呢,想了很久啊!!!,
各種猜測都想了,最後突然想起會不會是 我在兩個項目 jdk 用的不一樣,而jdk版本不同,內部使用的類加載器會有所區別呢!–>到此,我算終於快破案了其實!!(最後發現還真的是這個原因!!)

六. 原因確定–> 類加載器不同–>不同的原因如下–> jdk版本

後面由於我上面的猜測懷疑jdk版本所引起的類加載器不同導致,於是我趕緊看了看我兩個項目,突然看到我的 源碼spring 是用的jdk9, 而我的普通項目中是 jdk8. --> 這還沒有完,既然不同,爲了驗證我的猜測,於是,
我馬上把自己把自己普通項目的jdk 版本從 jdk8 切換到 jdk9 ,運行test, 查看結果–>
果然不出所料,這回bean中所標註了有 @postConstrut 的方法執行不了了,debug 到 jsr250Present 的獲取上,發現此值是 fasle–> 即跟進去看發現它所加載 類 Resouce 這個類所用的類加載器 變了,變成了和我源碼中同樣 的 classLoader 了,也是加載不到那個類,會異常返回false,–> 這下就完全解釋了!!
–> 但這裏又給我引出了幾個奇怪的問題了:
1.jdk9爲何加載不到 javax.annotation.Resouce???
2.jdk8 和 jdk9 的類加載器不同的xxxx
3.驗證@resouce 註解在spring自動裝配byName時對應jdk9版本時是否生效,肯定不
在這裏插入圖片描述
jdk8中:–順便複習遍byName自動裝配–https://github.com/wuda5/spring-relate/commit/02b8658c89a863d76464c93c1b72c705f2510067
在這裏插入圖片描述

七. jdk不同版本對應加載類所引起問題帶給我的思考

1.後面於是我查詢了很多資料,想找到我出現此問題的bug的佐證和依據,發現一個被翻譯的老外的文章寫的不錯,–> http://www.it1352.com/962789.html
以下是部分截圖:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章