Spring源碼解析 XML方式加載bean

繼承圖

Spring源碼擁有的類實在太多了,所以梳理下主要的類圖對研究代碼還是很有用的,Spring的配置從先前的XML的配置的容器ClassPathXmlApplicationContext,到現在的基於註解的AnnotationConfigApplicationContext容器,都在下圖展現。
在這裏插入圖片描述

加載Bean

我們本次內容主要探究下,Spring如何通過xml讀取Bean容器,無論基於註解還是XML,都有一個比較重要的方法就是AbstractApplicationContext抽象容器的refresh()方法。下面的代碼建議對照上面的類圖去看,這樣會印象深一些。

//AbstractApplicationContext 類
public void refresh() throws BeansException, IllegalStateException {
    .....
	ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    .....
}

//AbstractRefreshableApplicationContext 類
protected final void refreshBeanFactory() throws BeansException {
        .....
		DefaultListableBeanFactory beanFactory = createBeanFactory();
        /** 這裏的beanFactory是DefaultListableBeanFactory 
        同時抽象方法loadBeanDefinitions 由子類自定義去實現 **/
		loadBeanDefinitions(beanFactory);
		 .....
}

//AbstractXmlApplicationContext 類
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
     .....
     XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
     ...
     loadBeanDefinitions(beanDefinitionReader);
     .....
}

  1. 通過上面的各種過程調用,具體的加載bean定義會交給Bean讀取對象XmlBeanDefinitionReader 去處理,XmlBeanDefinitionReader繼承自AbstractBeanDefinitionReader
  2. 我們的這個抽象對象AbstractBeanDefinitionReader組合了BeanDefinitionRegistry接口屬性。
    注意:DefaultListableBeanFactory實現了這個BeanDefinitionRegistry接口,最後我們會發現,維護Bean定義對象集合的正是這個DefaultListableBeanFactory
  3. DefaultBeanDefinitionDocumentReader裏面的processBeanDefinition其實就包含了將讀取的文件轉化成
    BeanDefinitionHolder對象的過程,所以這個方法其實是我們最重要的方法體。
    BeanDefinitionHolder對象包含了私有屬性BeanDefinition。我們後面就是對這個BeanDefinitionHolder的處理
//DefaultBeanDefinitionDocumentReader類
protected void doRegisterBeanDefinitions(Element root) {
	 ....
	 parseBeanDefinitions(root, this.delegate);
	 ....
}
//DefaultBeanDefinitionDocumentReader類
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		//開始組建BeanDefinitionHolder對象
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// 這裏其實就是開始調我們的DefaultListableBeanFactory去處理
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
                //這裏getRegistry()就是之前在XmlBeanDefinitionReader類裏的DefaultListableBeanFactory的Registry對象
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			// Send registration event.
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

4.最後會將解析的BeanDefinitionHolder存到我們DefaultListableBeanFactory,這裏面的源碼如下

//DefaultListableBeanFactory 類

/** 裏面屬性 Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
//主要的方法
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition){ 
   .....
   this.beanDefinitionMap.put(beanName, beanDefinition);
   	.....
}

在這裏插入圖片描述

後記

對於閱讀源碼還是不求甚解,淺嘗輒止最好,以免調入調用的黑洞裏面去,難以自拔。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章