媒介
Spring设置文件读取流程原来是和http://www.cnblogs.com/xrq730/p/6285358.html一文放在一起的,这两天在看Spring自界说标签的时候,感受对Spring设置文件读取流程照旧研究得不足,因此将Spring设置文件读取流程部门从之前的文章拆出来单独成为一文。
为了看一下Spring设置文件加载流程,先界说一个bean.xml:
<?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-3.0.xsd"> <bean id="beanPostProcessorBean" class="org.xrq.action.BeanPostProcessorBean" /> <bean id="beanFactoryPostProcessorBean" class="org.xrq.action.BeanFactoryPostProcessorBean" /> <bean id="multiFunctionBean" class="org.xrq.action.MultiFunctionBean" init-method="initMethod"> <property name="propertyA" value="abc" /> </bean> </beans>
至于Bean是什么并不重要,有设置文件就够了。
Bean界说加载流程—-从Refresh到Bean界说加载前
首先看一下Bean加载前整个代码流程走向。Spring上下文刷新始于AbstractApplicationContext的refresh()要领:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
...
}
代码不全帖了,第7行的obtainFreshBeanFactory()要领进去:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
第2行的refreshBeanFactory()要领进去,它是AbstractApplicationContext的子类AbstractRefreshableApplicationContext中的要领:
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try{
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
首先第8行获取DefaultListableBeanFactory,然后执行第11行的要领,传入当前获取的BeanFactory,筹备加载Bean界说。BeanFactory中有存储了些什么数据在【Spring源码阐明】Bean加载流程概览一文中有画表格具体说明,看过表格的伴侣应该知道为什么第8行要获取的是DefaultListableBeanFactory而不是它的接口BeanFactory,因为Bean界说存储在Map<String, BeanDefinition>中,这个Map的位置就是在DefaultListableBeanFactory里,因此这里直接获取DefaultListableBeanFactory并作为参数层层向后传,加载完Bean界说后直接向Map<String, BeanDefinition>里put键值对。
看下loadBeanDefinitions要领,它是AbstractRefreshableApplicationContext子类AbstractXmlApplicationContext中的一个要领:
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
第3行的XmlBeanDefinitionReader是Bean加载的焦点类,先构建出来,后头代码没什么值得看的,直接看第13行代码,传入XmlBeanDefinitionReader:
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}