在對refreshBeanFactory()詳細解析之前,先來看看spring的applicationContext的繼承樹:

BeanFactory 簡介

ResourceLoader簡介
接下來進入正題:
refreshBeanFactory() 重新整理beanfactory
// AbstractRefreshableApplicationContext.java - 120
@Override
protected final void refreshBeanFactory() throws BeansException {
// 如果 ApplicationContext 中已經載入過 BeanFactory 了,銷燬所有 Bean,關閉 BeanFactory
// 注意,應用中 BeanFactory本來就是可以多個的,這裡可不是說應用全域性是否有 BeanFactory,而是當前ApplicationContext 是否有 BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 初始化一個 DefaultListableBeanFactory,為什麼用這個,我們馬上說。
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 用於 BeanFactory 的序列化
beanFactory.setSerializationId(getId());
// 下面這兩個方法很重要,
// 設定 BeanFactory 的兩個配置屬性:是否允許 Bean 覆蓋、是否允許迴圈引用
customizeBeanFactory(beanFactory);
// 載入 Bean 到 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);
}
}
複製程式碼
整個過程主要分為了三個步驟:
1.resource定位
2.beanDefinition的載入。
3.向ioc容器註冊beanDefinition的過程。
複製程式碼
loadBeanDefinitions(beanFactory) 載入 Bean:
// AbstractXmlApplicationContext.java 80
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 給這個 BeanFactory 例項化一個 XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 初始化 BeanDefinitionReader,其實這個是提供給子類覆寫的,
initBeanDefinitionReader(beanDefinitionReader);
// 重點來了,繼續往下
loadBeanDefinitions(beanDefinitionReader);
}
複製程式碼
讀取配置的操作在 XmlBeanDefinitionReader 中,其負責載入配置、解析。 // AbstractXmlApplicationContext.java 120
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//如果呼叫的構造器是new ClassPathXmlApplicationContext(String path, Class<?> clazz),獲取其路徑下的資源
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
//如果構造器呼叫的的是 new ClassPathXmlApplicationContext(String configLocation),獲取其資源
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
複製程式碼
這裡兩個分支都是在載入bean例項,過程類似,只分析reader.loadBeanDefinitions(configResources);
//AbstractBeanDefinitionReader.java L177
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int counter = 0;
for (Resource resource : resources) {
//這裡用了典型的模板模式,實際呼叫的是XmlBeanDefinitionReader#loadBeanDefinitions
counter += loadBeanDefinitions(resource);
}
return counter;
}
複製程式碼
//XmlBeanDefinitionReader.java L314
/**
* Load bean definitions from the specified XML file.
* 從xml里載入bean例項
*/
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
...
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
複製程式碼