欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

【死磕 Spring】----- IOC 之 注册 BeanDefinition

程序员文章站 2022-03-13 09:31:16
原文出自: "http://cmsblogs.com" 获取 Document 对象后,会根据该对象和 Resource 资源对象调用 方法,开始注册 BeanDefinitions 之旅。如下: 首先调用 方法实例化 BeanDefinitionDocumentReader 对象,然后获取统计前 ......

原文出自:

获取 document 对象后,会根据该对象和 resource 资源对象调用 registerbeandefinitions() 方法,开始注册 beandefinitions 之旅。如下:

    public int registerbeandefinitions(document doc, resource resource) throws beandefinitionstoreexception {
        beandefinitiondocumentreader documentreader = createbeandefinitiondocumentreader();
        int countbefore = getregistry().getbeandefinitioncount();
        documentreader.registerbeandefinitions(doc, createreadercontext(resource));
        return getregistry().getbeandefinitioncount() - countbefore;
    }

首先调用 createbeandefinitiondocumentreader() 方法实例化 beandefinitiondocumentreader 对象,然后获取统计前 beandefinition 的个数,最后调用 registerbeandefinitions() 注册 beandefinition。

实例化 beandefinitiondocumentreader 对象方法如下:

    protected beandefinitiondocumentreader createbeandefinitiondocumentreader() {
        return beandefinitiondocumentreader.class.cast(beanutils.instantiateclass(this.documentreaderclass));
    }

注册 beandefinition 的方法 registerbeandefinitions() 是在接口 beandefinitiondocumentreader 中定义,如下:

    void registerbeandefinitions(document doc, xmlreadercontext readercontext)
            throws beandefinitionstoreexception;

从给定的 document 对象中解析定义的 beandefinition 并将他们注册到注册表中。方法接收两个参数,待解析的 document 对象,以及解析器的当前上下文,包括目标注册表和被解析的资源。其中 readercontext 是根据 resource 来创建的,如下:

    public xmlreadercontext createreadercontext(resource resource) {
        return new xmlreadercontext(resource, this.problemreporter, this.eventlistener,
                this.sourceextractor, this, getnamespacehandlerresolver());
    }

defaultbeandefinitiondocumentreader 对该方法提供了实现:

    public void registerbeandefinitions(document doc, xmlreadercontext readercontext) {
        this.readercontext = readercontext;
        logger.debug("loading bean definitions");
        element root = doc.getdocumentelement();
        doregisterbeandefinitions(root);
    }

调用 doregisterbeandefinitions() 开启注册 beandefinition 之旅。

    protected void doregisterbeandefinitions(element root) {
        beandefinitionparserdelegate parent = this.delegate;
        this.delegate = createdelegate(getreadercontext(), root, parent);

        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);
        // 解析
        parsebeandefinitions(root, this.delegate);
        // 解析后处理
        postprocessxml(root);

        this.delegate = parent;
    }

程序首先处理 profile属性,profile主要用于我们切换环境,比如切换开发、测试、生产环境,非常方便。然后调用 parsebeandefinitions() 进行解析动作,不过在该方法之前之后分别调用 preprocessxml()postprocessxml() 方法来进行前、后处理,目前这两个方法都是空实现,交由子类来实现。

    protected void preprocessxml(element root) {
    }
    
    protected void postprocessxml(element root) {
    }

parsebeandefinitions() 定义如下:

    protected void parsebeandefinitions(element root, beandefinitionparserdelegate delegate) {
        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);
        }
    }

最终解析动作落地在两个方法处:parsedefaultelement(ele, delegate)delegate.parsecustomelement(root)。我们知道在 spring 有两种 bean 声明方式:

  • 配置文件式声明:<bean id="studentservice" class="org.springframework.core.studentservice"/>
  • 自定义注解方式:<tx:annotation-driven>

两种方式的读取和解析都存在较大的差异,所以采用不同的解析方法,如果根节点或者子节点采用默认命名空间的话,则调用 parsedefaultelement() 进行解析,否则调用 delegate.parsecustomelement() 方法进行自定义解析。

至此,doloadbeandefinitions() 中做的三件事情已经全部分析完毕,下面将对 bean 的解析过程做详细分析说明。