【Spring Framework 深入】—— IoC容器初始化 -> Bean定义资源的载入解析

Bean定义资源的载入解析,Resource是Xml文件的资源描述符(resource descriptor)

回到XmlBeanDefinitionReader的loadBeanDefinitions(Resource …)方法

XmlBeanDefinitionReader.java

@Override
    public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
        //将读入的XML资源进行特殊编码处理
        return loadBeanDefinitions(new EncodedResource(resource));
    }

    /**
     * Load bean definitions from the specified XML file.
     * @param encodedResource the resource descriptor for the XML file,
     * allowing to specify an encoding to use for parsing the file
     * @return the number of bean definitions found
     * @throws BeanDefinitionStoreException in case of loading or parsing errors
     */
    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        ......
        try {
            //得到资源Resource的IO流
            InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
                //将InputStream包装成InputSource解析流
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                //这里是实际处理Resource的过程
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            }
            finally {
                inputStream.close();
            }
        }
        ......
    }

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
            //将XML文件转换为DOM对象,解析过程由documentLoader实现
            Document doc = doLoadDocument(inputSource, resource);
            //启动对Document对象的解析过程
            return registerBeanDefinitions(doc, resource);
        }
        ......
    }

protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
        //documentLoader将Resource解析成DOM对象并返回
        return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
                getValidationModeForResource(resource), isNamespaceAware());
    }

DocumentLoader将Bean定义资源Resource转换成Document对象

DefaultDocumentLoader.java

//使用标准的JAXP解析器将载入的Bean定义资源解析成DOM Document实例
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
            ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
        //创建文件解析器工厂
        DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
        if (logger.isDebugEnabled()) {
            logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
        }
        //创建文档解析器
        DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
        //解析Bean定义资源
        return builder.parse(inputSource);
    }

该解析过程调用JavaEE标准的JAXP标准进行处理。
至此Spring IoC容器根据定位的Bean定义资源文件,将其加载读入并转换成为Document对象过程完成。

转换成Document对象后,XmlBeanDefinitionReader委派DefaultBeanDefinitionDocumentReader进行实际的解析工作

XmlBeanDefinitionReader.java

//Register the bean definitions contained in the given DOM document.
    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        int countBefore = getRegistry().getBeanDefinitionCount();
        //BeanDefinitionDocumentReader只是一个接口,
        //实际委派给DefaultBeanDefinitionDocumentReader进行解析
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }
    protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
        return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
    }
    private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;

BeanDefinitionDocumentReader接口通过registerBeanDefinitions方法调用其实现类DefaultBeanDefinitionDocumentReader对Document对象进行解析

DefaultBeanDefinitionDocumentReader.java

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

protected void doRegisterBeanDefinitions(Element root) {
        // Any nested <beans> elements will cause recursion in this method. In
        // order to propagate and preserve <beans> default-* attributes correctly,
        // keep track of the current (parent) delegate, which may be null. Create
        // the new (child) delegate with a reference to the parent for fallback purposes,
        // then ultimately reset this.delegate back to its original (parent) reference.
        // this behavior emulates a stack of delegates without actually necessitating one.
        BeanDefinitionParserDelegate parent = this.delegate;
        //具体的解析过程由BeanDefinitionParserDelegate实现
        //BeanDefinitionParserDelegate中定义了Spring Bean定义XML文件的各种元素
        this.delegate = createDelegate(getReaderContext(), root, parent);

        if (this.delegate.isDefaultNamespace(root)) {
            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)) {
                    return;
                }
            }
        }
        //在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性
        preProcessXml(root);
        //从Document的根元素开始解析Bean定义的Document对象  
        parseBeanDefinitions(root, this.delegate);
        //在解析Bean定义之后,进行自定义的解析,增强解析过程的可扩展性  
        postProcessXml(root);

        this.delegate = parent;
    }

protected BeanDefinitionParserDelegate createDelegate(
            XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {

        BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
        delegate.initDefaults(root, parentDelegate);
        return delegate;
    }

上述的流程图如下:
这里写图片描述

解析过程的核心函数是parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)

DefaultBeanDefinitionDocumentReader.java

//Parse the elements at the root level in the document
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        //根节点是否使用了Spring默认的XML命名空间
        //BeanDefinitionParserDelegate定义了常量,String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                //元素节点是否使用了默认XML命名空间
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    if (delegate.isDefaultNamespace(ele)) {
                        //使用Spring的Bean规则解析元素节点
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        //没有使用Spring默认的XML命名空间,则使用用户自定义的解析规则解析元素节点
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            //Document的根节点没有使用Spring默认的命名空间,则使用用户自定义的解析规则解析Document根节点  
            delegate.parseCustomElement(root);
        }
    }
//使用Spring的Bean规则解析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);
        }
        //元素节点是<Beans>
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            // recurse 递归
            doRegisterBeanDefinitions(ele);
        }
    }

<Import><Alias>元素解析在DefaultBeanDefinitionDocumentReader中已经完成,对Bean定义资源文件中使用最多的<Bean>元素交由BeanDefinitionParserDelegate来解析,源码如下

DefaultBeanDefinitionDocumentReader.java

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // Register the final decorated instance.
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }
BeanDefinitionParserDelegate.java

//解析<Bean>元素的入口
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
        return parseBeanDefinitionElement(ele, null);
    }
//解析Bean定义资源文件中的<Bean>元素,这个方法中主要处理<Bean>元素的id,name和别名属性 
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) 
//详细对<Bean>元素中配置的Bean定义其他属性进行解析,除id,name和别名属性三个以外的其他属性数据  
public AbstractBeanDefinition parseBeanDefinitionElement(
            Element ele, String beanName, BeanDefinition containingBean)

注意,在上述解析过程中,只是根据元素的配置信息创建了相应的定义类BeanDefinition,没有创建和实例化Bean对象,依赖注入才会使用这些记录信息创建和实例化具体的Bean对象

<Bean>常用的属性配置:id、name、alias和property

篇幅较大。。。留到以后再详细学习。

向IoC容器注册BeanDefinition

通过Spring IoC容器对Bean定义资源的解析后,IoC容器大致完成了管理Bean对象的准备工作,即初始化过程,但是最为重要的依赖注入还没有发生,现在在IoC容器中BeanDefinition存储的只是一些静态信息,接下来需要向容器注册Bean定义信息才能全部完成IoC容器的初始化过程。
回到DefaultBeanDefinitionDocumentReader的processBeanDefinition函数,BeanDefinitionParserDelegate 的BeanDefinitionParserDelegate 函数完成后,返回封装BeanDefinition的BeanDefinitionHold对象,接下来,调用BeanDefinitionReaderUtils的registerBeanDefinition方法向IoC容器注册解析的Bean。
函数调用流程图:
这里写图片描述

DefaultBeanDefinitionDocumentReader.java

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // Register the final decorated instance.
                //向容器注册BeanDefinition的入口      
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // Send registration event.
            //注册完成后,发送注册事件
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }

待续。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值