源碼深入解析spring 的初始化方法 initMethod (標有註解的@postConstruct的方法)--極度細緻!

一.說在前面(結論思考)

@postConstruct 所標註的方法 內部是靠的spring提供的兩個後置處理器(InitDestroyAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor)共同 協調分佈處理完成的。 這2點也是網上絕大部人沒講明白的,很多人都只是說到一個,其實我之前看源碼也是以爲一個,結果,後面由於xxx 我發現了是兩個!!還有就是他們各種如何協調作用完成工作的?是各自又是在 bean 的生命週期的哪一個階段`起的作用?

二.弄清InitDestroyAnnotationBeanPostProcessor CommonAnnotationBeanPostProcessor的關係

這兩個後置處理器還是父子關係:`InitDestroyAnnotationBeanPostProcessor` 和 `CommonAnnotationBeanPostProcessor`

1.CommonAnnotationBeanPostProcessor

a.提供的方法 postProcessMergedBeanDefinition 可以看作處理解析註解入口–> 其時它處理 @Resouce 的字段注入
–> 所以可以看到它自身 維護了一個 緩存injectionMetadataCache <String, InjectionMetadata> 這個 map 的value是包含了 每一個bean類所依賴屬性 字段(可能多個) 是被 標註由 @Resouce 的 封裝爲 InjectionMetadata對象,key爲beanName
–> 他裏面有個方法是 autowireResouce(Beanfactory,LookupElenment,string) 完成對 依賴字段的處理
具體的 postProcessMergedBeanDefinition 被調用及作用見下圖很重要!:
在這裏插入圖片描述

2.InitDestroyAnnotationBeanPostProcessor

其實只是解析了 bean上面有標註 @PostConstruct、@ PreDestroy 的方法們,
–> 所以我們同可以在它裏面維護了1個緩存lifecycleMetadaCache<Class, LifecycleMetada> ,這個 map就是在解析的過程中完成 --> value是包含了 每一個bean類(只能1個,還不能靜態源碼看到!) 是被 標註由 @PostConstruct、@ PreDestroy的 先各自對應封裝的方法集合,後兩個集合方法共同封裝爲 InjectionMetadata對象,key爲beanClass

– 剛上面提到的–>解析具體是在何時哪個階段完成的呢?
–> 其實是在上面的子類 CommonAnnotationBeanPostProcessor 的 postProcessMergedBeanDefinition被調用時候執行!

3.總結關係

  1. 註解解析爲緩存: @PostConstruct、@ PreDestroy 及 @Rerosuce 的解析是發生在–》bean生命週期的實例化後,pupulate 設置屬性前, 通過 【apply_Merged_BeanDefinitionPostProcessors】利用 合併後置處理器接口方法調用到 CommonAnnotationBeanPostProcessor 他的postProcessMergedBeanDefinition邏輯完成註解(方法,字段)解析放到了其和父類的兩個緩存map裏面,具體使用在下面
  2. 註解方法調用:(我們暫時不關注註解字段 即 @Rerosuce解析的緩存使用)
    註解方法如–》 @PostConstruct 註解的方法被調用反射處理 A 中方法是在 整個init 初始化階段的before階段即:【apply_BeanPostProcessors_BeforeInitialization】獲取到所有的處理器們,其中執行到 InitDestroyAnnotationBeanPostProcessor. postProcessBeforeInitialization,這裏面會發生 “先取後用” 的操作,見下圖:

在這裏插入圖片描述

注意:其實2.中所說的獲取到處理器執行到 InitDestroyAnnotationBeanPostProcessor 不是直接到的!!,這裏有一個小點!!即我們經常看到的獲取所有的處理器們 getBeanPostProcessors()這個方法其實返回的是 bean工廠裏面單獨所維護 的一個後置處理器的一個集合 List<BeanPostProcessor> beanPostProcessors,而其實InitDestroyAnnotationBeanPostProcessor 這個後置處理器是沒有在這個集合中的!!但是他的所繼承的子類CommonAnnotationBeanPostProcessor是在的 ,即我們剛說的調用都是掉的父類處理器
CommonAnnotationBeanPostProcessor只不過 這個後置處理器根本沒有重寫 父類處理器InitDestroyAnnotationBeanPostProcessor的方法 postProcessBeforeInitialization,所以調用鏈是直接進入 到InitDestroyAnnotationBeanPostProcessor裏面的!

插一句(可能插的有點長哈):
(這裏其實可以解釋到爲啥jdk版本不同,到這@postConstuct 和 @Resouce 可能不生效!的原因,–> 因爲 CommonAnnotationBeanPostProcessor 這個後置處理器是來處理了 a. @PostConstruct、@ PreDestroy + b.@Resource 兩大類註解的實現, 爲啥說是兩個大類呢? 因爲,a. 類註解是用在方法上面表示init相關, 而 b.類 @Resouce 是處理字段上面自動注入的類似 @Autowired,(從類圖方法也可以看到) 在這裏就顯得有點另類了,我當時也非常奇怪爲啥它明明是來處理對象的依賴字段屬性注入相關的,爲啥它要放到這個後置處理器中處理,而非是像@Autowired 是由 AutowireAnnotationBeanPostProcessor 來處理的,–> 後面我的理解是: @Resouce 和初始化的註解 都不是spring框架自帶的,而 @Autowired 卻是,這也就是說, @Resouce 等註解因爲它不屬於spring的一部分即它可能是因爲jdk的版本不同是加載不到類的,如jdk9,11由於xx就是加載不上的!,而我們的 @Autowired 是非常極度常用且是spring自己所帶的所以一定能保證它的解析加載依賴屬性正常,即 AutowireAnnotationBeanPostProcessor 是可以被放入到spirng容器裏,重點來了!如果我們講有可能出問題的 @Resouce 等註解的解析功能也放到 AutowireAnnotationBeanPostProcessor裏面話,那麼就可能會導致 這個非常重要的基礎處理器都無法放入spring中即spring就基本失效了!,所以 spring 給分開了保證即使由於外部原因 CommonAnnotationBeanPostProcessor 無法正常加入spring,也能基本實現大部分功能! )

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