继承图
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);
.....
}
后记
对于阅读源码还是不求甚解,浅尝辄止最好,以免调入调用的黑洞里面去,难以自拔。