Spring原始碼閱讀——Bean的載入和獲取過程
阿新 • • 發佈:2019-01-04
我們經常使用Spring,並且也都瞭解其大概原理。我想我們一定會對Spring原始碼的解讀有迫切的渴望。
我也如此。所以,我打算閱讀一下Spring的原始碼。再此之前,我也為此準備了很多。包括,去複習熟練java反射,理解常用的設計模式。當然,這些複習筆記也會在今後的複習中順便記錄在我的csdn部落格。(當然,可能寫的不好,也可能理解不正確(可以一起交流嘛)。但是樂於分享總歸是好的。)
首先看下spring的各個元件。
BeanFactoryTest.java
先從表面上可以看到 bean的載入可大致可以分為:從xml讀取bean的資訊載入到Spring容器中,通過xml配置的id從Spring容器反射得到這個類的例項物件。 現在,我們進行詳細分析 1.Resource resource = new ClassPathResource("spring/ioc/beans.xml"); 我們通過Sring Core模組的工具從本地獲得了xml資源,並生成Resource物件。這一過程就不詳細跟進了。 2.通過XmlBeanFactory來建立BeanFactory物件。 直接debug進入
3.首先我們會跟進 DefaultSingletonBeanRegistry 其中有靜態物件需要例項化。至於為什麼會跟進這個類,我們來看下類的繼承關係就知道了(為什麼會先例項其中的靜態類,可以複習以下java物件的例項順序)
4.接著會進入DefaultListableBeanFactory建立裡面的靜態物件例項以及執行裡面的靜態模組
5.通過類載入器注入DefaultListableBeanFactory物件 然後又例項化了一個存放DefaultListableBeanFactory的map
6.接著再執行XmlBeanFactory的構造方法,其中把配置檔案Resource賦值給了resource
7.執行this.reader.loadBeanDefinitions(resource); //可以看到這個步驟是要把resource載入到容器中去了。這裡是整個資源載入進入的切入點。
8.接著再跟進,直到進入public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException ;方法
9.對匯入資源再進行一定包裝處理後進入doLoadBeanDefinitions(inputSource, encodedResource.getResource()); //對於encode我們是比較熟悉的 肯定是處理編碼相關的
10.現在已經進入到了XmlBeanDefinitionReader.java, 再包裝處理(畢竟xml檔案規則什麼的驗證啊 獲取比較麻煩,不知道你暈了沒有) xml還是包裝成了Document委託給DocumentLoader去處理執行
12.經過documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); 最終我們獲取到了root,protected void doRegisterBeanDefinitions(Element root)這個方法,開始真正的解析已經處理過的資源。
13.解析完成後就是註冊了, debug到如下程式碼
14.可以看到在這裡,把bean存到了beanDefinitionMap中,
對於beanDefinitionMap是什麼,就是存在記憶體中的map,bean就存在裡面供外部獲取。
跟蹤了這麼多的原始碼,肯定有點亂。做下總結吧。 Spring中bean的載入過程 1.獲取配置檔案資源 2.對獲取的xml資源進行一定的處理檢驗 3.處理包裝資源 4.解析處理包裝過後的資源 5.載入提取bean並註冊(新增到beanDefinitionMap中) 至於bean的獲取,那就比上面的簡單多了。 斷點進入AbstractBeanFactory
入口
當你看到這條語句,你就豁然開朗了,
HelloSpring.java<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="hello" class="bean.HelloSpring" lazy-init="false"></bean> </beans>
package bean; /** * Created by yuyufeng on 2016/11/17. */ public class HelloSpring { private String name; public HelloSpring() { System.out.println("##HelloSpring.HelloSpring初始化……………………………………"); } public HelloSpring(String name) { this.name = name; } public void sayHello(String something){ System.out.println("hello"+something); } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "HelloSpring{" + "name='" + name + '\'' + '}'; } }
BeanFactoryTest.java
package spring.ioc; import bean.HelloSpring; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; /** * Created by yuyufeng on 2016/11/18. * Spring中Bean的載入過程 */ public class BeanFactoryTest { public static void main(String[] args) { //spring如何初始化有兩種方式 beanFactory applicationContext Resource resource = new ClassPathResource("spring/ioc/beans.xml"); BeanFactory beanFactory = new XmlBeanFactory(resource); HelloSpring helloSpring = (HelloSpring) beanFactory.getBean("hello"); helloSpring.sayHello("張三"); } }
先從表面上可以看到 bean的載入可大致可以分為:從xml讀取bean的資訊載入到Spring容器中,通過xml配置的id從Spring容器反射得到這個類的例項物件。 現在,我們進行詳細分析 1.Resource resource = new ClassPathResource("spring/ioc/beans.xml"); 我們通過Sring Core模組的工具從本地獲得了xml資源,並生成Resource物件。這一過程就不詳細跟進了。 2.通過XmlBeanFactory來建立BeanFactory物件。 直接debug進入
3.首先我們會跟進 DefaultSingletonBeanRegistry 其中有靜態物件需要例項化。至於為什麼會跟進這個類,我們來看下類的繼承關係就知道了(為什麼會先例項其中的靜態類,可以複習以下java物件的例項順序)
4.接著會進入DefaultListableBeanFactory建立裡面的靜態物件例項以及執行裡面的靜態模組
5.通過類載入器注入DefaultListableBeanFactory物件 然後又例項化了一個存放DefaultListableBeanFactory的map
6.接著再執行XmlBeanFactory的構造方法,其中把配置檔案Resource賦值給了resource
7.執行this.reader.loadBeanDefinitions(resource); //可以看到這個步驟是要把resource載入到容器中去了。這裡是整個資源載入進入的切入點。
8.接著再跟進,直到進入public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException ;方法
9.對匯入資源再進行一定包裝處理後進入doLoadBeanDefinitions(inputSource, encodedResource.getResource()); //對於encode我們是比較熟悉的 肯定是處理編碼相關的
10.現在已經進入到了XmlBeanDefinitionReader.java, 再包裝處理(畢竟xml檔案規則什麼的驗證啊 獲取比較麻煩,不知道你暈了沒有) xml還是包裝成了Document委託給DocumentLoader去處理執行
12.經過documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); 最終我們獲取到了root,protected void doRegisterBeanDefinitions(Element root)這個方法,開始真正的解析已經處理過的資源。
13.解析完成後就是註冊了, debug到如下程式碼
14.可以看到在這裡,把bean存到了beanDefinitionMap中,
對於beanDefinitionMap是什麼,就是存在記憶體中的map,bean就存在裡面供外部獲取。
跟蹤了這麼多的原始碼,肯定有點亂。做下總結吧。 Spring中bean的載入過程 1.獲取配置檔案資源 2.對獲取的xml資源進行一定的處理檢驗 3.處理包裝資源 4.解析處理包裝過後的資源 5.載入提取bean並註冊(新增到beanDefinitionMap中) 至於bean的獲取,那就比上面的簡單多了。 斷點進入AbstractBeanFactory
入口
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);進入之後
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException { // Quick check on the concurrent map first, with minimal locking. RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName); if (mbd != null) { return mbd; } return getMergedBeanDefinition(beanName, getBeanDefinition(beanName)); }再進入
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));我們發現又進入了 DefaultListableBeanFactory.java,是不是有種熟悉的感覺。
當你看到這條語句,你就豁然開朗了,
BeanDefinition bd = this.beanDefinitionMap.get(beanName);就是之前載入bean放入到的map嗎? 其實整個過程還是比較容易理解的,就是裡面的包裝解析很複雜