(一)Spring IoC源码-1.容器的初始化-04获取并注册BeanDefinitions

在文章IoC源码-容器的基础的末尾,我们讲到从XML中加载Bean定义分为两个步骤来完成的。

  1. 加载Xml文件,并封装成Document 实例。
  2. 根据Document实例获取并注册Bean信息。

上文IoC源码-获取Document实例已经介绍了如何“加载Xml文件,并封装成Document 实例”。本文将详细讲解如何“根据Document实例注册Bean信息”。

org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(Document, Resource)

//根据Document实例注册Bean信息
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    //实例化BeanDefinitionDocumentReader
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    //记录本次注册前已经注册的Bean个数
    int countBefore = getRegistry().getBeanDefinitionCount();
    //注册Bean
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    //返回本次注册的Bean个数
    return getRegistry().getBeanDefinitionCount() - countBefore;
}

实例化BeanDefinitionDocumentReader的详细代码如下。

private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;
...
...
...
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
    return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
}

可以看出,documentReader的实际类型是DefaultBeanDefinitionDocumentReader。进入其registerBeanDefinitions方法内部

@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    this.readerContext = readerContext;
    logger.debug("Loading bean definitions");
    Element root = doc.getDocumentElement();
    doRegisterBeanDefinitions(root);
}

到了最关键的部分,doRegisterBeanDefinitions方法开始真正开始注册BeanDefinitions了。

/**
 * 使用给定的<beans/>元素注册每个bean
 */
protected void doRegisterBeanDefinitions(Element root) {
    //???
    BeanDefinitionParserDelegate parent = this.delegate;
    this.delegate = createDelegate(getReaderContext(), root, parent);

    //处理profile
    if (this.delegate.isDefaultNamespace(root)) {
        //获取元素的profile属性
        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
        if (StringUtils.hasText(profileSpec)) {
            String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                    profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                if (logger.isInfoEnabled()) {
                    logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                            "] not matching: " + getReaderContext().getResource());
                }
                return;
            }
        }
    }
    //解析前处理。空方法。留给子类按需实现。模板方法模式
    preProcessXml(root);
    //解析并注册BeanDefinition
    parseBeanDefinitions(root, this.delegate);
    //解析后处理。空方法。留给子类按需实现。模板方法模式
    postProcessXml(root);

    this.delegate = parent;
}

如想详细了解模板方法模式请移步设计模式(22)-模板方法模式。下面parseBeanDefinitions方法看看是如何解析并注册BeanDefinition的。

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    //如果元素是默认标签,按照处理默认标签的方式来处理
    if (delegate.isDefaultNamespace(root)) {
        //获取元素的所有子节点
        NodeList nl = root.getChildNodes();
        //遍历所有的子节点,即"import", "alias", "bean".
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                //如果子节点是默认标签
                if (delegate.isDefaultNamespace(ele)) {
                    parseDefaultElement(ele, delegate);
                }
                else {//如果子节点是自定义标签
                    delegate.parseCustomElement(ele);
                }
            }
        }
    }
    else {//如果元素是自定义标签,按照自定义标签的方式来处理
        delegate.parseCustomElement(root);
    }
}

可以看出,Spring对于默认标签和自定义标签的处理方式是不同的。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值