技术文技术干货程序员

SpringIOC源码阅读—BeanDefinitionDocu

2017-11-21  本文已影响0人  激情的狼王

BeanDefinitionDocumentReader的作用,通过命名后缀就可以推断出它的职责是解析文件然后调用生成BeanDefinition的接口完成注册。
我们来看它的doRegisterBeanDefinitions注册bean)方法:

protected void doRegisterBeanDefinitions(Element root) {
        
        BeanDefinitionParserDelegate parent = this.delegate;
        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;
                }
            }
        }
        //核心步骤
        preProcessXml(root);
        parseBeanDefinitions(root, this.delegate);
        postProcessXml(root);

        this.delegate = parent;
    }

核心步骤我已经加上了注释,其中parseBeanDefinitions(root, this.delegate)方法中root就是xml文件的实例,我们跟进去

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        //是否是DefaultNamespace
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            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);
        }
    }

这段代码上来就判断是否是默认的Namespace,根据断点可以看到root的Namespace是http://www.springframework.org/schema/beans,对比一下beans.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
 <bean id="user" class="xz.quartz.analysis.User"></bean>
</beans>

这个是beans的xmlns属性的值,这个我们先跳过继续往后读可以看到是循环解析Node的过程,也就是解析bean节点,继续看第二个注释,跟进去

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标签、bean标签、beans标签想必大家都遇见过。

我们这次是注册的bean标签,所以程序会进入bean的处理:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        //这里通过delegate拿到了bean实例
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // Register the final decorated instance.
                //注册最终的bean实例
                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));
        }
    }

这段代码我们可以看到Spring是通过BeanDefinitionParserDelegate拿到bean对象的实例然后完成注册的,我们下篇文章讲的就是这个过程。
接下来我们聊一下上面留下的一个问题,Namespace的值是http://www.springframework.org/schema/beans也就是beans的xmlns属性的值,所以才会分上面import标签、bean标签、beans标签来分别处理。
也就是意味着我们可以自定义标签去解析,去处理,这也证明了Spring扩展性是毋庸置疑的,bean生成的过程是可插拔的。这个特性也是对一个框架最基本的要求

上一篇下一篇

猜你喜欢

热点阅读