1.前言
2.spring源码obtainFreshBeanFactory()介绍
3.总结
1.前言
github源码地址(带注释):
https://github.com/su15967456...
我们上篇博客对spring的核心方法有了一个大概的认知,从今往后的几篇博客,我们将会将这几个方法进行深入地分析。
话不多说,先上图。
今天我们要介绍的obtainFreshBeanFactory()方法,其主要功能就是:
1.创建容器对象 DefaultListableBeanFactory
2.加载各种配置文件的属性到当前工厂中,最重要的就是封装成BeanDefinition
2.spring源码obtainFreshBeanFactory()介绍
接下来我们来分析一下这个方法,首先往这个方法里点击:
/**
* Tell the subclass to refresh the internal bean factory.
* @return the fresh BeanFactory instance
* @see #refreshBeanFactory()
* @see #getBeanFactory()
*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//初始化BeanFactory,并进行xml文件读取,并将得到的BeanFactory记录在当前实体的属性中
refreshBeanFactory();
return getBeanFactory();//返回当前实体的beanFactory属性
}
注释上告诉我们:主要就是生成一个bean工厂,我们可以继续观察refreshBeanFactory()方法。
/**
* This implementation performs an actual refresh of this context's underlying
* bean factory, shutting down the previous bean factory (if any) and
* initializing a fresh bean factory for the next phase of the context's lifecycle.
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
//如果有bean工厂了,先销毁掉
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建DefaultListableBeanFactory对象
DefaultListableBeanFactory beanFactory = createBeanFactory();
//每个容器都有自己的id,为了序列化指定id,可以从id反序列化到beanFactory对象
beanFactory.setSerializationId(getId());
//定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖,可以通过子类重写
customizeBeanFactory(beanFactory);
//初始化documentReader,并进行对xml文件进行解析
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
我们可以一目了然地看到,这个方法的前几步是十分简单而明了的:
1.创建一个bean工厂对象
2.设置一下容器的id
3.设置一下beanFactory的相关属性(包括是否允许覆盖同名称的不同定义的对象以及循环依赖,可以通过子类重写) 如果不清楚括号内容也没关系,主要就是有些属性以后要用到,我们这里要先进行一下初始化
4.对xml文件进行解析(这是一个封装方法,我们还要往里面继续查看,看看spring是如何将xml文件读取到容器中的)
我们继续debug,进入loadBeanDefinitions(beanFactory)方法;
/**
* Loads the bean definitions via an XmlBeanDefinitionReader.
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see #initBeanDefinitionReader
* @see #loadBeanDefinitions
*/
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//Create a new XmlBeanDefinitionReader for the given BeanFactory.
//适配器模式
//创建一个xml的beanDefinitionReader,并通过回调设置到beanFactory中
//beanFactory和applicationContext没有办法直接读取xml,就交给beanDefinitionReader进行,这就是适配器模式
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
// 给reader对象设置环境对象
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
//设置一个entity,用它来读取本地的xsd或者dtd文件,来完成相关的解析工作
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
//设计模式,适配器模式
//初始化beanDefinitionReader对象,此处设置配置文件是否需要验证
initBeanDefinitionReader(beanDefinitionReader);
//开始完成beanDefinition的加载
loadBeanDefinitions(beanDefinitionReader);
}
可以看出,大概进行了如下的操作:
创建一个XmlBeanDefinitionReader,通过XmlBeanDefinitionReader来完成beanDefinition的加载
这里使用了适配器模式:就是beanFactory本身没办法进行xml文件(配置文件)的读取,所以要借助beanDefinitionReader类进行对配置文件的读取,要让beanDefinitionReader做一个适配。(就像手机没办法直接从插座中获取电源,要借助适配器来充电。)
所以把beanFactory交给beanDefinitionReader,让beanDefinitionReader读取文件,封装成beanDefinition,加入beanFactory容器中。
/**
* Actually load bean definitions from the specified XML file.
* @param inputSource the SAX InputSource to read from
* @param resource the resource descriptor for the XML file
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
* @see #doLoadDocument
* @see #registerBeanDefinitions
*/
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 此处获取xml文件的document对象,这个解析过程是由documentLoader完成的,
// 从string[] -> StringResources -> resources
// 最终将resources解析成一个个document文档,根据文档信息封装成BeanDefinition对象
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
} catch (BeanDefinitionStoreException ex) {
throw ex;
} catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
然后我们一直往loadBeanDefinitions(beanDefinitionReader);里debug,会发现两个方法:
1.doLoadDocument(inputSource, resource);
2.registerBeanDefinitions(doc, resource);
注意,spring里面do开头的方法才是做实事的方法
这里先加载了一下文件,然后再创建了一下beanDefinition并且往factory注册了一下。至于具体的业务逻辑,可以先不去看,因为我们看源码的时间不是很长,我们大概知道流程就可以了,拘泥于细节的旋涡可能会劝退。
3.总结
今天我们大概总结了一下obtainFreshBeanFactory()方法,该方法主要有两个作用:
1.创建容器对象 DefaultListableBeanFactory
2.加载各种配置文件的属性到当前工厂中,封装成BeanDefinition