美文网首页技术文技术干货程序员
SpringIOC源码阅读—BeanDefinitionDocu

SpringIOC源码阅读—BeanDefinitionDocu

作者: 激情的狼王 | 来源:发表于2017-11-21 15:55 被阅读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生成的过程是可插拔的。这个特性也是对一个框架最基本的要求

    相关文章

      网友评论

        本文标题:SpringIOC源码阅读—BeanDefinitionDocu

        本文链接:https://www.haomeiwen.com/subject/qslwvxtx.html