spring Bean創建過程詳解


復習一下spring實現IOC的源碼流程

准備工作:

​ 強烈建議大家從git上拉取spring源碼來學習Spring源碼。因為里面相較於IDEA生成的會有注釋,里面有的方法會有注釋看起來會省力一點。

​ 以下都是用5.0.2版本來做闡述。

bean創建的流程圖

寫在前面:建議大家一定要自己用實例跑一遍,做好記錄。如果只是看看會非常抽象。此流程圖作為梗概,便於加強記憶和理解,新手或無基礎的有個印象即可。等跟隨本文走通一遍,在回過頭看這個圖,或許會有收獲

springbean lifecycle.jpg

源碼走一遍

bean的定義

  1. 這是我的bean目錄結構,只是做一個例子

image.png

  1. 獲取核心容器對象,bean最后都會放在此容器對象中

        *   ApplicationContext的三個實現類
        *   ClassPathXmlApplicationContext  它可以加載類路徑下的配置文件,要求必須在類路徑下
        *   FileSystemXmlApplicationContext  可以加載任意路徑下的配置文件,必須有訪問權限
        *   AnnotationConfigApplicationContext 用於讀取注解創建容器的
        
        這里我用ClassPathXmlApplicationContext來做演示
        
       public class MyTest {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        }
    }
    

快速開始

  1. 建議用IDEA的debug模式來觀察Spring的IOC過程

    image.png

    • 進入到此類的構造方法中image.png

      • 查看setConfigLocations,就是將配置文件加載到configLocations里去image.png
    • 向下執行,查看refresh()image.png

      • this.prepareRefresh(): 此方法是准備工作,大家感興趣可以點進去看一下,可以看到里面是獲取時間,獲取環境信息的一些設置。

      • this.obtainFreshBeanFactory(): 這一步是創建beanFactory,並且讀取Bean的信息,源碼注釋中還有寫到

        // Tell the subclass to refresh the internal bean factory.會告訴子類去刷新內部bean工廠
        
        • this.refreshBeanFactory:

          	 * This implementation performs an actual refresh of this context's underlying
          	 * bean factory, shutting down the previous bean factory (if any) and
          	 * initializing a fresh bean factory for the next phase of the context's lifecycle.
          	 
          	 這個實現類的方法會刷新容器中的beanFactory,關閉之前存在的並且初始化新的beanFactory
          

          image.png

      • 利用this.createBeanFactory() 創建了一個beanFactory,類型為DefaultListableBeanFactory

      • 這個類接着往下走:this.loadBeanDefinitions(beanFactory);

        	 * Load bean definitions into the given bean factory, typically through
        	 * delegating to one or more bean definition readers.
        	 
        	 這個方法會將beandefinitionsReader讀取到的bean definitions放入bean工廠,我們以上提出的三種
        	 注入方式都會走到這里,將bean信息丟進去
        
    • 返回上述 refresh()

      • this.prepareBeanFactory(beanFactory); 設置和忽略一些對象值

      • this.postProcessBeanFactory(beanFactory); 空方法可自定義擴展

      • this.invokeBeanFactoryPostProcessors(beanFactory);

        	 * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
        	 * respecting explicit order if given.
        	 * <p>Must be called before singleton instantiation.
        	 
        	 實例化所有beanFactory組件
        
      • registerBeanPostProcessors(beanFactory);

        Instantiate and register all BeanPostProcessor beans,  //先注冊再調用
        
      • initApplicationEventMulticaster(); 觀察者模式監聽器, 監聽組件的相關狀態,並決定相關調用方法。

      • finishBeanFactoryInitialization(beanFactory); 重要!!

        	 * Finish the initialization of this context's bean factory,
        	 * initializing all remaining singleton beans.
        	 
        	 完成了容器bean factory的初始化,並且初始化其他的bean單例對象
        
    • beanFactory.preInstantiateSingletons(); 實例化方法

      • 此方法最后this.getBean(beanName)

        • 繼續image.png

        • Return an instance, which may be shared or independent, of the specified bean.
          
          注釋已經很清楚了,此方法會返回一個實例,就是我們的bean對象
          

          image.png

      • 進入到createBean方法中image.png

      • 繼續進入![image-20200714221630608](/Users/hjj/Library/Application Support/typora-user-images/image-20200714221630608.png)

      • 繼續進入

        image.png

        image.png

        Instantiate the given bean using its default constructor.
        
        這個方法注釋說明了實例化對象是用構造器完成的
        
        • 繼續看他如何構造的image.png

        • image.png

        • image.png

          ca 就是Constructor,從這里我們基本可以看出容器內,bean對象的實例化
          是利用反射的基本原理,獲取類構造器,然后newInstance來實現的
          
      • 以上就是bean對象實例化的基本過程,下面是實例化完成后的初始化過程

      • 回到這里,實例化完成后

        image.png
        image.png

        注釋說明了在populateBean完成bean的初始化

      • 繼續image.png

        會看到在此方法里會調用前置和后置處理器來初始化Bean
        
    • 以上就完成了bean的實例化過程,文章開頭的那個圖剛開始有點懵,但是一旦跑完一遍bean的實例化過程,再次結合圖,就清晰了很多。本文只是簡單的跟隨debug順序,完整的走了一遍bean實例化的過程,還有特殊情況並沒有討論,后期會重新用新文章再來拓展。

如有不足還請指正。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM