Spring源码之 obtainFreshBeanFactory
在Spring IOC容器启动过程中,需要先去初始化beanFctory,这就是obtainFreshBeanFactory 方法,去读spring 的bean配置文件,将xml配置文件中的配置转换成BeanDefinition,加载到BeanFactory当中。
一、首先从ClassPathXmlApplicationContext 构造方法说起
测试代码如图:
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ApplicationContext 代表 IOC容器,ClassPathXmlApplicationContext 是 ApplicationContext的实现类,该实现类从类路径下加载配置文件。
- ClassPathXmlApplicationContext 的构造方法
ClassPathXmlApplicationContext类中构造方法:
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);
this.setConfigLocations(configLocations);
if (refresh) {
this.refresh();
}
}
- this.setConfigLocations(configLocations);
将配置文件路径赋值给configLocations,后边源码中会将配置文件解析为Resource来使用。
- this.refresh();
调用的是父类 AbstractApplicationContext 中的refresh方法。
AbstractApplicationContext类的refresh方法:
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var5) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt", var5);
this.destroyBeans();
this.cancelRefresh(var5);
throw var5;
}
}
}
- this.obtainFreshBeanFactory();
这个refresh方法中的 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
就是我们本次要分析的重点。
AbstractApplicationContext类中的obtainFreshBeanFactory方法:
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
this.refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
- this.refreshBeanFactory();
AbstractApplicationContext是一个抽象类,this.refreshBeanFactory(); 调用的是 AbstractApplicationContext 的子 AbstractRefreshableApplicationContext中的refreshBeanFactory方法。
AbstractRefreshableApplicationContext类的refreshBeanFactory方法:
protected final void refreshBeanFactory() throws BeansException {
// 判断是否已经实例化好了beanFactory,如果实例化好了,就要做销毁和关闭。
if (this.hasBeanFactory()) {
this.destroyBeans();
this.closeBeanFactory();
}
try {
// 创建 DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
// 执行序列化id
beanFactory.setSerializationId(this.getId());
// 设置默认覆盖同名bean,默认允许bean之间循环依赖
this.customizeBeanFactory(beanFactory);
// 对xml配置文件读取和解析
this.loadBeanDefinitions(beanFactory);
synchronized(this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException var5) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
}
}
this.loadBeanDefinitions(beanFactory); 方法中就开始对xml配置文件读取和解析的相关工作。
AbstractXmlApplicationContext 类中的 loadBeanDefinitions 方法:
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 实例化 beanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 获取系统运行参数
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
// 设置解析xml校验文件的 ResourceEntityResolver
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
this.initBeanDefinitionReader(beanDefinitionReader);
this.loadBeanDefinitions(beanDefinitionReader);
}
this.loadBeanDefinitions(beanDefinitionReader); 最终调用的是 XmlBeanDefinitionReader 中
XmlBeanDefinitionReader类中 的 loadBeanDefinitions 方法:
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (this.logger.isInfoEnabled()) {
this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!((Set)currentResources).add(encodedResource)) {
throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
} else {
int var5;
try {
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 解析 xml 文件
var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
} finally {
inputStream.close();
}
} catch (IOException var15) {
throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
} finally {
((Set)currentResources).remove(encodedResource);
if (((Set)currentResources).isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
return var5;
}
}
doLoadBeanDefinitions 方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
// 加载 xml 文件,得到 Document
Document doc = this.doLoadDocument(inputSource, resource);
// 根据返回的 Document 注册Bean信息
return this.registerBeanDefinitions(doc, resource);
} catch (BeanDefinitionStoreException var4) {
throw var4;
} catch (SAXParseException var5) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var5.getLineNumber() + " in XML document from " + resource + " is invalid", var5);
} catch (SAXException var6) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var6);
} catch (ParserConfigurationException var7) {
throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var7);
} catch (IOException var8) {
throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var8);
} catch (Throwable var9) {
throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var9);
}
}