繼承圖
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);
.....
}
- 通過上面的各種過程調用,具體的加載bean定義會交給Bean讀取對象XmlBeanDefinitionReader 去處理,XmlBeanDefinitionReader繼承自AbstractBeanDefinitionReader。
- 我們的這個抽象對象AbstractBeanDefinitionReader組合了BeanDefinitionRegistry接口屬性。
注意:DefaultListableBeanFactory實現了這個BeanDefinitionRegistry接口,最後我們會發現,維護Bean定義對象集合的正是這個DefaultListableBeanFactory。 - 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);
.....
}
後記
對於閱讀源碼還是不求甚解,淺嘗輒止最好,以免調入調用的黑洞裏面去,難以自拔。