Spring底層原理
前言
? 離上一篇文章記錄差不多過了半年左右的時間吧,這段時間很多面試準備,知識點的學習基本被我轉移到了書面筆記上,秋招仍在繼續,你我怎能懈怠!特撿起上半年的老本,繼續自己的CSDN博客之途,
? 看過我之前寫的文章的小伙伴肯定都有一個感受,啊寫的好基礎呀!沒錯是的,之前無論是技術知識的積累還是知識層面的廣度和深度,都近似一個小白在寫雜談…
? 這段很長時間的離開希望能讓以后我的分享提升一個檔次,至于為什么要堅持寫博客?
- 互聯網時代軟體行業技術開源精神的普及,分享技術是一件有助于自己,更幫助其他人從而達到共贏的很棒的事情,
- 幫助自己鞏固記憶知識點,好記性不如爛筆頭,同時費曼學習法教會我們如果能把別人講懂,說明我們已經熟練掌握了該知識點,
- 自己喜歡閱讀和寫作這兩件事,將自己想要表達的觀點和看法寫在文章里,是一件很有成就感的事情,不管有沒有人閱讀,負面評論什么的,自己從中可以獲取到樂趣,
目標
? 由于仍處于秋招白熱化期間,我可能有時沉浸在自己面經的復習中,但我計劃至少兩天寫一篇原創文章,希望可以完成!
正文
? 我們知道Spring是Jave EE里面劃時代的輕量級框架設計,代替了之前重量級的EJB技術(Enterprise JavaBean),可以解決物件依賴問題,降低耦合性,同時提供宣告式事務管理功能,
? Spring兩個核心功能為 控制反轉(IoC)和提供面向切面編程(AOP),
?今天我們就來了解下Spring的核心IoC容器,它是怎么匯入bean并進行實體化物件操作的?
匯入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,
BeanDefinition
?上述幾種方式可以為我們的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
?上面我們知道經過bean的定義決議程序,我們需要呼叫 getBean() 來實體化物件了,IoC容器是怎么一步步實體化物件的呢?
?我們可以通過原始碼打斷點跟隨著getBean()的呼叫堆疊一步步地分析~
總體呼叫堆疊為如下所述:
getBean() ----> doGetBean() ----->getSingleton() ----->createBean() ------>doCreateBean(),到這里我們停一下,這一步就是真正的創建我們的bean實體物件的程序,
?通過查看原始碼我們知道它呼叫createBeanInstance()方法通過反射來創建物件(早期物件),注意此時物件只是一個空殼物件,并不能直接構成我們最后的單例物件(Spring的IoC容器默認是單例的),這里我們不得不簡單科普一下Spring中的三級快取了,不然咱們無法繼續下去,
Spring三級快取
一級快取:就是大名鼎鼎的單例快取池,用于保存所有的單實體 bean,
singletonObjects = new ConCurrentHashMap<>();
終于看到ConCurrentHashMap的實際應用場景了hh,
三級快取:就是在createBeanInstance() 方法后創建的早期物件存放的地方,
singletonFactories = new HashMap<>();
我們總結:
- 所有的物件創建的程序中,都會去把自己的早期物件暴露到三級快取中去,
- 針對代理物件的時候,從三級快取到二級快取會經過一次代理,創建完畢后,就會洗掉2級快取,把單例物件存盤到單例快取池中,
? 緊接著上述創建早期物件,我們通過addSingletonFactory() 將早期物件暴露到三級快取中,再呼叫populateBean() 設定早期物件的屬性,如果發現其中依賴其他bean,則對其他bean執行同樣的步驟,如果出現回圈依賴的問題(即A依賴B,B依賴A),Spring的三級快取可幫我們解決這個問題,我們在開發中并沒有注意到這個問題,
? 以上就是今天總結分享的Spring匯入bean的三種方式以及匯入后bean的生命周期,由于博主也是沒有作業經驗的校招程式員,所以有很多地方說的不是很清楚甚至會引起誤解,大家可以提出來我一定會悉心聽取意見,
? 如果喜歡我的文章可以點點贊關注我,我也計劃至少兩天一篇原創文章,如果你能看到這里說明你肯定是一名熱愛學習的人,真誠希望我們能為了自己的目標或者夢想不斷努力,不斷學習,希望大家都能得到自己想要的! 我是 promise,一名喜歡思考人生,喜歡講大道理的程式員,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/171715.html
標籤:其他
