1.流程概述
IOC容器启动时会先将元数据(Configuration MetaData,即开发人员事先准备的XML或Annntation配置信息等)加载到容器环境中,然后再对这些元数据进行解析,将解析得到的BeanDefinition信息进一步编组成相应的BeanDefinitionHolder对象,最后再将编组对象进行注册,从而结束启动工作。
以XML为例,BeanFactory启动时需要XmlBeanDefinitionReader通过loadBeanDefinitions方法将元数据资源加载到上下文环境中,以此作为容器的启动入口。
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
BeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
reader.loadBeanDefinitions(new ClassPathResource("beans.xml"));
2.加载
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
private DocumentLoader documentLoader = new DefaultDocumentLoader();
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
……
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
……
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
……
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
}
// catch BeanDefinitionStoreException、SAXParseException等
……
}
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource, getEntityResolver(),
this.errorHandler, getValidationModeForResource(resource), isNamespaceAware());
}
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// DefaultBeanDefinitionDocumentReader
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 获取容器之前已注册在案的BeanDefinition数量
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
// 返回新注册成功的BeanDefinition数量
return getRegistry().getBeanDefinitionCount() - countBefore;
}
}
如上代码所示,XmlBeanDefinitionReader加载元数据时首先需要得到元数据的输入流(InputSource),其后再在doLoadBeanDefinitions方法中完成如下两项工作:
- 调用DefaultDocumentLoader的loadDocument方法,利用SAX技术将XML元数据解析成Document对象。
public class DefaultDocumentLoader implements DocumentLoader {
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
return builder.parse(inputSource);
}
}
- 调用XmlBeanDefinitionReader的registerBeanDefinitions方法完成后续的解析、编组和注册工作。
3.解析和编组
需要注意的是,XmlBeanDefinitionReader在registerBeanDefinitions方法中完成注册之前,实际上还需要先将Document对象进一步解析成BeanDefinition。默认情况下,这项解析工作由DefaultBeanDefinitionDocumentReader来完成。
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}