離上一篇文章記錄差不多過了半年左右的時間吧,這段時間很多面試準備,知識點的學習基本被我轉移到了書面筆記上,秋招仍在繼續,你我怎能懈怠!特撿起上半年的老本,繼續自己的CSDN部落格之途。
看過我之前寫的文章的小夥伴肯定都有一個感受,啊寫的好基礎呀!沒錯是的,之前無論是技術知識的積累還是知識層面的廣度和深度,都近似一個小白在寫雜談…
這段很長時間的離開希望能讓以後我的分享提升一個檔次,至於為什麼要堅持寫部落格?
由於仍處於秋招白熱化期間,我可能有時沉浸在自己面經的複習中,但我計劃至少兩天寫一篇原創文章。希望可以完成!
我們知道Spring是Jave EE裡面劃時代的輕量級框架設計,代替了之前重量級的EJB技術(Enterprise JavaBean),可以解決物件依賴問題,降低耦合性,同時提供宣告式事務管理功能。
Spring兩個核心功能為 控制反轉(IoC)和提供面向切面程式設計(AOP)。
今天我們就來了解下Spring的核心IoC容器,它是怎麼匯入bean並進行範例化物件操作的?
第一個問題我們首先要知道我們通過哪幾種方式可以為IoC容器匯入bean?
xml方式
xml作為最基本的設定方式,其實是比較重量級比較繁瑣的一種方式,我們在xml檔案中宣告一個個的 <bean標籤,指定bean的id和要匯入的全類名。
Java類設定
使用Java類定義Spring設定。使用@Configuration註解需要作為設定的類。(表示該類將定義Bean)
@Configuration
public class ApplicationContextConfig{
@Bean
public String message() {
return "hello";
}
}
開發中我們用的最多的是元件註解,@Component, 常見的有@Controller, @Repository, @Service。
上述幾種方式可以為我們的IoC容器匯入bean,那麼問題來了,我們匯入IoC容器中的bean 被 Spring 識別成什麼了呢,怎麼進行範例化的呢?
我們知道我們可以通過容器提供的 getBean( )方法獲取到對應id的bean物件,但是在 getBean() 之前做了哪些操作呢?
我們就要了解一下BeanDefinition這個物件了,我們被註解標記的類被JVM類載入器載入到記憶體中形成對應的BeanDedifinition的bean定義物件,儲存在一個map集合(BeanDefinitionMap)中。如下圖:
相信很多朋友都沒聽說過Spring裡面的這個bean定義物件,沒關係,我們學習新知識都是從一開始什麼都不知道到了解概念再到熟練,精通。
單單BeanDefinition可不能直接範例化,裡面需要涉及到一個介面,BeanFactoryPostProcessor,我們可以把它理解為在範例化物件之前可以修改我們的bean定義物件即BeanDedinition物件,這個介面中的一個實現類BeanDefinitionRegistryPostProcessor可以完成類似「設計小組」的功能,對位元組碼進行解析,這個介面的另外一個實現類可以實現類似「稽核小組」的功能,用於修改 bean定義物件。
聽到這裡可能很多小夥伴已經雲裡霧裡了,「這什麼亂七八糟的,你的文筆就這,就這??」
別急,我可以拿人給大家打個不恰當的比喻,一個已經範例化的bean物件可以看成是一個已經18歲的成年人了。
這個BeanDefinition我們可以把它看作我們人最初的形態——受精卵,我們以後長成人的基因已經在這裡確定了,那上面所說的BeanFactoryPostProcessor可以對bean定義物件作修改的嘛,沒事啊,我們受精卵也可以作修改啊,不是有個「人類基因組計劃」嘛,基因工程可以改變bean定義物件啊。之後getBean() 獲取到範例物件,此時我們知道還有一個BeanPostProcessor介面(注意這個和上面的介面不一樣!),這個就相當於我們現在流行的整容變性啊,之後真正成長成我們想要的樣子了。(說多了都是淚啊!)
這就是匯入到IoC容器後bean被Spring識別的過程。
上面我們知道經過bean的定義解析過程,我們需要呼叫 getBean() 來範例化物件了,IoC容器是怎麼一步步範例化物件的呢?
我們可以通過原始碼打斷點跟隨著getBean()的呼叫棧一步步地分析~
總體呼叫棧為如下所述:
getBean() ----> doGetBean() ----->getSingleton() ----->createBean() ------>doCreateBean(),到這裡我們停一下,這一步就是真正的建立我們的bean範例物件的過程。
通過檢視原始碼我們知道它呼叫createBeanInstance()方法通過反射來建立物件(早期物件),注意此時物件只是一個空殼物件,並不能直接構成我們最後的單例物件(Spring的IoC容器預設是單例的)。這裡我們不得不簡單科普一下Spring中的三級快取了,不然咱們無法繼續下去。
一級快取:就是大名鼎鼎的單例快取池,用於儲存所有的單範例 bean。
singletonObjects = new ConCurrentHashMap<>();
終於看到ConCurrentHashMap的實際應用場景了hh。
三級快取:就是在createBeanInstance() 方法後建立的早期物件存放的地方。
singletonFactories = new HashMap<>();
我們總結:
緊接著上述建立早期物件,我們通過addSingletonFactory() 將早期物件暴露到三級快取中,再呼叫populateBean() 設定早期物件的屬性,如果發現其中依賴其他bean,則對其他bean執行同樣的步驟,如果出現迴圈依賴的問題(即A依賴B,B依賴A),Spring的三級快取可幫我們解決這個問題,我們在開發中並沒有注意到這個問題。
以上就是今天總結分享的Spring匯入bean的三種方式以及匯入後bean的生命週期,由於博主也是沒有工作經驗的校招程式設計師,所以有很多地方說的不是很清楚甚至會引起誤解,大家可以提出來我一定會悉心聽取意見。
如果喜歡我的文章可以點點贊關注我,我也計劃至少兩天一篇原創文章。如果你能看到這裡說明你肯定是一名熱愛學習的人,真誠希望我們能為了自己的目標或者夢想不斷努力,不斷學習,希望大家都能得到自己想要的! 我是 promise,一名喜歡思考人生,喜歡講大道理的程式設計師。