媒介
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); } }