1. 程式人生 > 其它 >這些面試官常問的開發面試題你都掌握好了嗎?瞬間高大上了!

這些面試官常問的開發面試題你都掌握好了嗎?瞬間高大上了!

這些面試官常問的開發面試題你都掌握好了嗎?瞬間高大上了!

二、Spring生命週期的大膽猜測

這裡分享一個閱讀原始碼的小技巧:捉大放小,連蒙帶猜!8字真言,我們在閱讀原始碼過程中,因為你要知道,每一個被開源出來的優秀框架,其原始碼的體系都是極其龐大複雜的,我們不能面面俱到,所以在看原始碼過程中一定不能被細枝末節纏住,一定要先理清楚整個框架的一個大致思想和大致的框架體系,再去搞那些細枝末節,其效率會好很多,其次在看原始碼過程中,我們一定要大膽的去想,去猜測,如果這個功能讓你自己去寫,你會怎麼實現!

我們今天學習SpringBean的生命週期也是按照這個8字真言去學習,通過我們之前所學,Spring大致有以下的功能:

  1. 他會幫我們自動的建立物件然後儲存起來!
  2. 他會幫我們完成屬性的填充!
  3. 如果我們設定了Aop的功能,他會幫我們自動的代理,實現切面功能!

我們從平常的使用中,至少可以得知以上的三點,如果讓你自己去實現,必會如何實現呢?

  • 首先他既然能夠幫我們自己建立物件,那麼他肯定是通過反射來建立的,通過反射來建立,就必定繞不過去要使用Class物件建立,那麼我們如何獲取Class物件呢? 去掃描專案,將指定的包下的加了註解的類檔案切割獲取Class名稱,通過反射載入Class名稱,反射建立java物件!
  • 我們要完成屬性的填充,為了方便和效能方面,我肯定會把這些建立好的物件儲存起來,無疑Map容器是最合適的!
  • 我們在建立一個物件完成之後,反射拿到裡面的屬性,如果需要填充,我們先去我們之前儲存的容器裡面去取,取不出來在反射吧這個依賴的屬性創建出來,然後填充進物件再儲存在容器裡面,從而完成了屬性的注入!
  • 填充完成屬性之後,我們那當前物件,取與Aop邏輯進行對比,判斷是否需要代理,不需要則建立完成,儲存進Map容器,需要代理則對當前這個類進行jdk或者cglib的代理然後再儲存進容器裡面!

於是乎,我們自己實現了一個Spring管理一個Bean的所有過程,畫個圖,他大概長這樣!

自己實現看起來,整個流程就很清晰,掃描、建立、注入、代理、儲存一應俱全,但是Spring的實現方式遠比我們自己實現的要複雜的多得多!

三、Spring的生命週期流程

Spring作者希望,Spring再著手管理一個Bean的時候,它希望能夠讓Spring的使用者能夠插手,Spring把一個類物件變成一個Java Object的每一步,怎麼理解呢?

比如我們買了一棟新房子,這個房子需要取裝修,你自己去裝修誠然不夠專業,不能夠面面俱到,所以是我們就找了一個裝修公司幫助我們裝修新房,於是裝修公司就開始預先畫好的圖紙進行裝修,但是在裝修的過程中,你為了讓自己的新家更加溫馨,你想掛一些壁畫在牆上,但是圖紙上卻沒有!於是你就找裝修公司,要求裝修公司在新家的牆上掛上一些壁畫!裝修公司在接受到你的請求之後,就吩咐裝修的工人在圖紙之外去給你在牆上掛上壁畫之後,然後再接著裝修!

上面這個小故事有 這樣幾個角色,我們把它和Spring對照起來!

  • 你:代表框架的使用者!
  • 新房:代表一個Class檔案,你自己也能夠裝修,但是不夠專業,所以交給裝修公司! 那麼你自己建立物件可能某些使用用起來很麻煩,所以我們交給了Spring容器!
  • 裝修公司:代表著Spring容器!
  • 圖紙:代表預設步驟,Spring原本就存在的步驟!
  • 工人:Spring提供的各種介面!我們可以通過Spring工廠提供的介面做各種自定義的配置!

上面的小故事,大致可以描述Spring生命週期的核心思想!Spring再對一個Class檔案例項化成具體的Spring Bean的時候,它提供了各種介面,由我們自己實現!然後再例項化過程中,不同的時機,去呼叫不同的介面!從而完成Spring的整個生命週期的建立!

Spring的生命週期大致分為以下部分!

  1. 掃描專案,將專案指定目錄下的Class檔案轉換為Class物件!

  2. 讀取Class物件屬性包裝為BeanDefinition,然後儲存再一個Map中!(不難理解,他是為了後續建立或者讀取這個類的資訊更加方便取而創立的)

  3. 將全部的類轉化為 BeanDefinition 並儲存之後,開始呼叫第一個回撥介面BeanFactoryPostProcessor#postProcessBeanFactory()!

    • 它的呼叫時機是將掃描到的Class檔案轉換為 BeanDefinition 之後呼叫的,我們可以通過回撥的方法獲取所有的BeanDefinition ,而後續的所有對Class的操作都是基於BeanDefinition 操作的,所以,我們可以通過修改它,來改變後續的流程!
  4. 先從當前的容器物件取當前要建立的物件,當取出來的物件為null時開始著手建立物件!

  5. 做一系列的驗證,比如驗證這個類是否被排除、是否正在建立中、是否有依賴Bean【@DependsOn】註解、是否時單例等等!

  6. 驗證通過之後,開始通過反射建立這個物件!

  7. 合併BeanDefinition ,這裡涉及到Spring之前版本使用的父子容器的概念,屬於另外一個知識點不做講解!

  8. 判斷當前物件是不是單例、是不是支援迴圈引用、是不是正在建立等!

  9. 執行第二個介面回撥InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()方法!

    • 它的執行時機時例項化完成之後,屬性填充之前,它的返回值是一個布林值,當返回false時,不做自動屬性填充!
  10. 執行第三個介面回撥InstantiationAwareBeanPostProcessor#postProcessProperties()方法!

    • 他的執行時機是,例項化之後,屬性填充檢查之後,屬性填充之前!它會返回一個屬性,後續的屬性填充會使用這個方法返回的值!我們可以在這個方法裡面修改對應Bean的注入的值!
  11. 填充屬性到物件!

  12. 呼叫第四個回撥介面BeanNameAware#setBeanName()方法!

    • 呼叫時機:屬性填充給完畢後,呼叫初始化方法之前;它的功能是能獲取bean的Name!
  13. 呼叫第五個回撥介面BeanClassLoaderAware#setBeanClassLoader()

    • 呼叫時機:BeanNameAware之後,他的功能是傳入bean的類載入器;
  14. 呼叫第六個回撥介面BeanFactoryAware#setBeanFactory()!

    • 呼叫時機:BeanClassLoaderAware之後,用於設定beanFactory!
  15. 呼叫第七個回撥介面BeanPostProcessor#postProcessBeforeInitialization()方法

    • 呼叫時機是部分Aware之後,初始化方法之前!傳入當前例項化好的物件和beanName,再初始化前做修改!
  16. 回撥第八個比較重要的生命週期的初始化方法,它可以是一個InitializingBean介面的bean,也可以是xml中配置的類,也可以是被加了@PostConstruct註解的方法!

    • 該方法內部邏輯可以使用者自己編寫,呼叫時機為:例項化完成之後呼叫!
  17. 回撥第九個回撥介面 BeanPostProcessor#postProcessAfterInitialization()方法!

    • 該方法的呼叫時機為初始化方法執行之後,這裡也是Bean例項化後的最後一步,也是SpringAop實現的重要的一步!
  18. 註冊銷燬方法,以便Spring容器銷燬的時候進行方法的銷燬!

整體的方法流程示例圖如下:

四、對應原始碼結構圖

寫在最後

學習技術是一條慢長而艱苦的道路,不能靠一時激情,也不是熬幾天幾夜就能學好的,必須養成平時努力學習的習慣。所以:貴在堅持!

最後再分享的一些BATJ等大廠20、21年的面試題,把這些技術點整理成了視訊和PDF(實際上比預期多花了不少精力),包含知識脈絡 + 諸多細節,由於篇幅有限,上面只是以圖片的形式給大家展示一部分。

領取方式:戳這裡即可免費領取

Mybatis面試專題

MySQL面試專題

併發程式設計面試專題