天天看點

看看Spring源碼(二)——bean執行個體化

首先來看一段代碼,看過上一節的朋友肯定對這段代碼并不陌生。這一段代碼诠釋了spring加載bean的完整過程,包括讀取配置檔案,掃描包,加載類,執行個體化bean,注入bean屬性依賴。

上一節介紹了spring是如何加載class檔案的,本節主要圍繞<code>finishbeanfactoryinitialization(beanfactory)</code>方法,聊聊spring是如何執行個體化bean的,從上面代碼片段中的注解不難看出,此方法主要的任務就是執行個體化非懶加載的單例bean。閑話少叙,看代碼。

上面代碼主要看最後一句<code>beanfactory.preinstantiatesingletons()</code>。<code></code>

<code></code>

此方法首先将加載進來的beandefinitionnames循環分析,如果是我們自己配置的bean就會走<code>else</code>中的<code>getbean(beanname)</code>,接着看。<code></code>

<code>dogetbean</code>方法内容太多,一段一段看。<code></code>

這裡主要看<code>object sharedinstance = getsingleton(beanname)</code>。<code></code>

這裡能看到,spring會把執行個體化好的bean存入<code>singletonobjects</code>,這是一個<code>concurrenthashmap</code>,<code></code>

當然這裡我們bean并未執行個體化過,是以這裡應該也不能get出什麼東西來,也就是傳回null了。<code>if</code>子句也就不會執行了。那麼接着看<code>else</code>子句的内容。<code></code>

這兩條驗證也都不會實作,接寫來就是重點了。<code></code>

在這裡拿到<code>rootbeandefinition</code>并check,并獲得bean的依賴,并循環疊代執行個體化bean。例如class a依賴于class b,就會先執行個體化b。下面的<code>if ... else ...</code>就是真正執行個體化bean的地方。其實真正執行個體化bean的方法是<code>createbean(beanname, mbd, args)</code>,隻是區分了<code>issingleton</code>或<code>isprototype</code>,兩者的差別在于,單例的(singleton)被緩存起來,而prototype是不用緩存的。首先看一下<code>createbean(beanname, mbd, args)</code>。<code>createbean</code>方法中除了做了一些執行個體化bean前的檢查準備工作外,最核心的方法就是<code></code>

由于這個過程涉及到的代碼都是一大坨,就不貼出所有代碼了。<code></code>

首先就是建立一個bean的執行個體且封裝到<code>beanwrapper</code>中,在這裡bean已經執行個體化了。具體的實作方法是在<code>org.springframework.beans.factory.support.simpleinstantiationstrategy.instantiate(rootbeandefinition beandefinition, string beanname, beanfactory owner)</code>中。<code></code>

在這裡不難看出執行個體化分兩種情況,如果沒有無參構造器是就生成cglib子類,否則就直接反射成執行個體。<code></code>

既然已經有了執行個體對象了,那麼,spring是如何将bean的屬性注入到bean的呢?傳回到上面的<code>docreatebean</code>方法中。往下看找到<code>populatebean(beanname, mbd, instancewrapper);</code>,内幕就在這裡。隻貼部分代碼:<code></code>

<code>findautowiringmetadata</code>方法能拿到使用了特定注解的屬性(field)、方法(method)及依賴的關系儲存到<code>checkedelements</code>集合<code>&lt;set&gt;</code>裡,然後再執行自己的<code>inject</code>方法。<code></code>

真正幹事的還是<code>injectedelement</code>的<code>inject</code>方法。<code></code>

其實别看代碼這麼多,最關鍵的部分就是:<code></code>

在這裡也就真相大白了,就是通過jdk反射特性,直接set值的。