您的位置:首页 > 编程语言 > Java开发

5、IoC容器的初始化(4)-由Document解析根节点

2018-01-26 14:35 246 查看
本文主要讨论Document的根元素解析过程。

 

1、调用XmlBeanDefinitionReader中的registerBeanDefinitions方法,注册包含在给定DOM文档中的BeanDefinitions。

  // XmlBeanDefinitionReader中
// 注册包含在给定DOM文档中的bean定义。
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 创建实际使用的{@link BeanDefinitionDocumentReader}
// 从XML文档读取bean定义。
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 获取容器中注册bean的数量
int countBefore = getRegistry().getBeanDefinitionCount();

//这里又用了委派模式;
//父类定义子类的接口;
//子类做具体实现子类做具体实现
//在DefaultBeanDefinitionDocumentReader中完成
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//统计bean的数量
return getRegistry().getBeanDefinitionCount() - countBefore;
}
具体看registerBeanDefinitions方法中调用的createBeanDefinitionDocumentReader();方法(创建实际使用的BeanDefinitionDocumentReader对象):

  //创建实际使用的BeanDefinitionDocumentReader对象
//用于解析Document对象
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
}
接着看documentReader.registerBeanDefinitions(doc, createReaderContext(resource));方法,主要实现根据“spring-beans”XSD解析BeanDefinitions

// DefaultBeanDefinitionDocumentReader
// 这个方法实现根据“spring-beans”XSD解析Bean Definitions
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
//得到xml的描述符
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
// 得到Document的根元素
Element root = doc.getDocumentElement();
//在给定的根<beans />元素中注册每个bean定义。
doRegisterBeanDefinitions(root);
}

看上面源码最后调用的一个方法,在给定的根<beans />元素中注册每个BeanDefinitions。

//在给定的根<beans />元素中注册每个bean定义。
protected void doRegisterBeanDefinitions(Element root) {

//任何嵌套的<beans>元素都将导致此方法的递归。
//在为了正确传播和保存<beans> default- *属性,
//跟踪当前(父)委托,可能为null。 创建
//新的(子)委托为了回退的目的而引用父对象,
//然后最终重置this.delegate回到其原始(父)参考。
//这个行为模拟了一堆委托,而实际上并不需要一个委托。

//BeanDefinitionParserDelegate 里面定义了Spring Bean定义的各种元素
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);

//...

// 解析Bean Definitions之前,进行自定义解析,增强扩展性
preProcessXml(root);
// 从Document的根节点元素进行解析
parseBeanDefinitions(root, this.delegate);
// 解析Bean Definitions之后,进行自定义解析,增强扩展性
postProcessXml(root);

this.delegate = parent;
}

上面源码的parseBeanDefinitions(root, this.delegate);,遍历节点根节点,根据具体的命名空间和解析规则解析Document的根节点元素:

  // 解析文档中根层的元素:"import", "alias", "bean".
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// Bean定义的Document对象是否使用了Spring定义的默认XML命名空间
if (delegate.isDefaultNamespace(root)) {
// 获取所有Document对象根元素的所有子节点
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
// 获得Document对象节点的XML元素节点
if (node instanceof Element) {
Element ele = (Element) node;
// 是否使用了Spring定义的默认XML命名空间
if (delegate.isDefaultNamespace(ele)) {
// 使用了默认的命名空间
// 使用Spring的Bean规则解析Bean节点
parseDefaultElement(ele, delegate);
}
else {
// 没有使用默认的命名空间
// 使用用户自定义规则解析Bean节点
delegate.parseCustomElement(ele);
}
}
}
}
else {
// 没有使用默认的命名空间
// 使用用户自定义规则解析Document根节点
delegate.parseCustomElement(root);
}
}
接着看上面源码parseDefaultElement(ele, delegate);方法,分别解析三种根节点的元素:"import","alias", "bean",根据不同的根节点使用不同的解析策略。

// DefaultBeanDefinitionDocumentReader
// 默认的Document根节点分别采用对应具体的解析流程
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析Import节点
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
// 解析Alias节点
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
// 解析Bean节点
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
// 递归解析解析节点
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}


下面来看一下解析Import节点相关代码:

// DefaultBeanDefinitionDocumentReader
// 解析Import节点
protected void importBeanDefinitionResource(Element ele) {
// 获取给定导入元素的location信息
String location = ele.getAttribute(RESOURCE_ATTRIBUTE);

// location属性值为空表示没有资源,直接返回
if (!StringUtils.hasText(location)) {
getReaderContext().error("Resource location must not be empty", ele);
return;
}

// 解析系统属性:例如“$ {user.dir来}”
location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);

Set<Resource> actualResources = new LinkedHashSet<Resource>(4);

//判断该位置是绝对还是相对URI
boolean absoluteLocation = false;
try {
absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
}
catch (URISyntaxException ex) {
//非绝对路径
//考虑到相对位置,不能转换为URI
//除非是着名的Spring前缀“classpath *:”
}

// 是否是绝对路径
if (absoluteLocation) {
try {
//使用资源读取器去加载给定路径的BeanDefinition资源
int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
if (logger.isDebugEnabled()) {
logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
}
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error(
"Failed to import bean definitions from URL location [" + location + "]", ele, ex);
}
}
else {
//没有URL - >考虑相对于当前文件的资源位置。
try {
int importCount;
// 把导入的location封装成相对路径资源
Resource relativeResource = getReaderContext().getResource().createRelative(location);
// 如果相对路径对应的资源存在
if (relativeResource.exists()) {
//使用资源读取器去加载给定路径的BeanDefinition资源
importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
actualResources.add(relativeResource);
}
// 如果相对路径对应的资源不存在
else {
// 获取Spring IoC容器资源读取器的基本路径
String baseLocation = getReaderContext().getResource().getURL().toString();
// 根据Spring IoC容器资源读取器的基本路径加载给定导如路径的资源
importCount = getReaderContext().getReader().loadBeanDefinitions(
StringUtils.applyRelativePath(baseLocation, location), actualResources);
}
if (logger.isDebugEnabled()) {
logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
}
}
catch (IOException ex) {
getReaderContext().error("Failed to resolve current resource location", ele, ex);
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",
ele, ex);
}
}

Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);
// 解析完,把容器发给其他资源处理事件
getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}


下面来看一下解析bean节点相关代码:

  // DefaultBeanDefinitionDocumentReader
// 处理给定的bean元素,解析bean定义并将其注册到注册表中。
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 通过BeanDefinitionHolder对BeanDefinition进行再封装
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//注册最终装饰的实例。
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 完成解析在IoC容器解析得到BeanDefinition之后发送注册事件
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}

         

a80f
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Spring