loadBeanDefinitions方法源碼跟蹤(二)

由於字數超過了限制,因此分紅了三篇,承接上篇:
https://www.jianshu.com/p/a0cfaedf3fc5java

代碼過寬,能夠shift + 鼠標滾輪 左右滑動查看node

3.parseDefaultElement

先跟蹤一個bean標籤,下面是對應的配置文件spring

<!--配置mapper.java掃描-->
<bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="cn.mrdear.mapper"/>
    <property name="properties">
        <value>
            mappers=tk.mybatis.mapper.common.Mapper
        </value>
    </property>
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>

由於是bean標籤,走的默認的名稱空間方法,因此走這個標籤的方法:sql

//3.若是該標籤屬於beans的名稱空間,則進入這個方法
//xmlns="http://www.springframework.org/schema/beans"
parseDefaultElement(ele, delegate);

這個方法的實如今DefaultBeanDefinitionDocumentReader類中,由於 標籤下有多個子標籤,因此每一個子標籤對應着一個方法 數組

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
        // 若是是嵌套的beans,那麼就會從新調用標記2中的一個方法進行遞歸
        doRegisterBeanDefinitions(ele);
    }
}


/**
* Process the given bean element, parsing the bean definition
* and registering it with the registry.
*
* 處理bean元素,解析成bean definition並註冊到工廠中
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   
    //3.1經過代理解析bean元素
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        
        //3.2若是有要求的話渲染beanDefinition
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            
            // Register the final decorated instance.
            //3.3註冊最終被渲染的實例到工廠中
            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));
    }
}

3.1 parseBeanDefinitionElement

跟蹤3.1標記的方法mybatis

進入BeanDefinitionParserDelegate類的parseBeanDefinitionElement方法app

//3.1經過代理解析bean元素
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);


/**
* Parses the supplied {@code <bean>} element. May return {@code null}
* if there were errors during parse. Errors are reported to the
* {@link org.springframework.beans.factory.parsing.ProblemReporter}.
* 
* 解析bean元素。若是解析過程當中發生錯誤則返回空
*/
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
    return parseBeanDefinitionElement(ele, null);
}


public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
    
    //拿bean標籤上的id
    String id = ele.getAttribute(ID_ATTRIBUTE);
    
    //拿bean標籤上的name屬性
    String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

    List<String> aliases = new ArrayList<String>();
    
    //有name屬性進入
    if (StringUtils.hasLength(nameAttr)) {
        
        //name屬性對應的name值若是有分隔符",; ",那麼切分紅數組
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
        
        //這些name值就是別名
        aliases.addAll(Arrays.asList(nameArr));
    }
    
    //指定了id就用id值做爲bean名稱
    String beanName = id;
    
    //若是沒有id,可是指定了name,就用name值做爲bean名稱
    if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
        
        //拿第一個name值做爲bean名稱,其他的仍是別名
        beanName = aliases.remove(0);
        if (logger.isDebugEnabled()) {
            logger.debug("No XML 'id' specified - using '" + beanName +
                         "' as bean name and " + aliases + " as aliases");
        }
    }

    if (containingBean == null) {
        
        //檢查bean名稱和別名是否已經被使用了,若是用了就報錯
        //同時把這個bean的名稱和別名加入代理的usedNames屬性中
        //private final Set<String> usedNames = new HashSet<String>();
        checkNameUniqueness(beanName, aliases, ele);
    }
    
    //直接進入這個方法
    AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    if (beanDefinition != null) {
        
        //既沒有指定id,也沒有指定name就走這裏面
        if (!StringUtils.hasText(beanName)) {
            try {
                
                //前面containingBean傳遞時爲null,這裏不走這個方法
                if (containingBean != null) {
                    beanName = BeanDefinitionReaderUtils.generateBeanName(
                        beanDefinition, this.readerContext.getRegistry(), true);
                }
                else {
                    
                    //生成一個bean名稱,beanName
                    //若是這個bean是內部bean,全限定名後加#號再加哈希值
                    //若是是頂層bean,那麼後面加#號再從0開始加數字,id已被註冊數字就增1,直到惟一
                    //好比:tk.mybatis.spring.mapper.MapperScannerConfigurer#0
                    beanName = this.readerContext.generateBeanName(beanDefinition);
                    
                    // Register an alias for the plain bean class name, if still possible,
                    // if the generator returned the class name plus a suffix.
                    // This is expected for Spring 1.2/2.0 backwards compatibility.
                    
                    //若是可能的話,若是生成器返回類名加後綴,則註冊一個別名,這個別名就是該類的類名。
                    //這是爲了向後兼容
                    String beanClassName = beanDefinition.getBeanClassName();
                    if (beanClassName != null &&
                        beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                        !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                        
                        //若是該類名沒有被使用,那麼註冊該類名做爲別名,好比:
                        //tk.mybatis.spring.mapper.MapperScannerConfigurer做爲
                        //tk.mybatis.spring.mapper.MapperScannerConfigurer#0的別名
                        aliases.add(beanClassName);
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Neither XML 'id' nor 'name' specified - " +
                                 "using generated bean name [" + beanName + "]");
                }
            }
            catch (Exception ex) {
                error(ex.getMessage(), ele);
                return null;
            }
        }
        String[] aliasesArray = StringUtils.toStringArray(aliases);
        
        //返回beanDefinition的持有者
        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    }

    return null;
}



/**
* Parse the bean definition itself, without regard to name or aliases. May return
* {@code null} if problems occurred during the parsing of the bean definition.
* 
* 不關注名稱和別名,只解析bean definition自身
*/
public AbstractBeanDefinition parseBeanDefinitionElement(
    Element ele, String beanName, BeanDefinition containingBean) {
    
    //解析的時候放入,解析完成彈出,這裏放入bean標籤,
    //若是還嵌套有子標籤,則後續放入子標籤
    //子標籤先彈出
    this.parseState.push(new BeanEntry(beanName));

    String className = null;
    if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
        
        //若是有指定class屬性,則拿到class屬性值
        className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    }

    try {
        String parent = null;
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
            
            //若是有指定parent屬性,則拿到parent屬性值
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }
        
        //3.1.1建立BeanDefinition並設置兩屬性
        AbstractBeanDefinition bd = createBeanDefinition(className, parent);
        
        //3.1.2將bean標籤上的屬性設置到bean definition中
        parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
        
        //若是bean標籤下有子標籤爲description,拿到標籤中的文本,設置到bean definition中
        bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
        
        //若是bean標籤下有子標籤爲meta,拿到他的key和value屬性,設置到bean definition中
        parseMetaElements(ele, bd);
        
        //若是bean標籤下有子標籤爲lookup-method,拿到他的name和bean屬性,設置到bean definition中
        parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
        
        //若是bean標籤下有子標籤爲replaced-method,設置bean definition 
        parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
        
        //若是bean標籤下有子標籤爲constructor-arg,設置bean definition的構造方式
        parseConstructorArgElements(ele, bd);
        
        //這個標籤比較經常使用,爲Property標籤
        //3.1.3解析Property的屬性設置到bean definition中
        parsePropertyElements(ele, bd);
        
        //有qualifier子標籤才走這個方法
        parseQualifierElements(ele, bd);
        
        //設置資源
        bd.setResource(this.readerContext.getResource());
        
        //這裏爲null
        bd.setSource(extractSource(ele));

        return bd;
    }
    catch (ClassNotFoundException ex) {
        error("Bean class [" + className + "] not found", ele, ex);
    }
    catch (NoClassDefFoundError err) {
        error("Class that bean class [" + className + "] depends on not found", ele, err);
    }
    catch (Throwable ex) {
        error("Unexpected failure during bean definition parsing", ele, ex);
    }
    finally {
        
        //解析的時候放入,解析完成彈出
        this.parseState.pop();
    }

    return null;
}

3.1.1 createBeanDefinition

跟蹤標記3.1.1ide

//3.1.1建立BeanDefinition並設置兩屬性
AbstractBeanDefinition bd = createBeanDefinition(className, parent);

/**
* Create a bean definition for the given class name and parent name.
*
* 經過給定的className和parentName建立beanDefinition
*/
protected AbstractBeanDefinition createBeanDefinition(String className, String parentName)
    throws ClassNotFoundException {

    return BeanDefinitionReaderUtils.createBeanDefinition(
        parentName, className, this.readerContext.getBeanClassLoader());
}

/**
* 此方法是BeanDefinitionReaderUtils的靜態方法
*
* Create a new GenericBeanDefinition for the given parent name and class name,
* eagerly loading the bean class if a ClassLoader has been specified.
*
* 經過給定的parentName和className穿件一個新的GenericBeanDefinition
* 若是指定了ClassLoader,就提早加載bean class
*/
public static AbstractBeanDefinition createBeanDefinition(
    String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {

    GenericBeanDefinition bd = new GenericBeanDefinition();
    bd.setParentName(parentName);
    if (className != null) {
        if (classLoader != null) {
            
            //接受的屬性是Object類型
            bd.setBeanClass(ClassUtils.forName(className, classLoader));
        }
        else {
            
            //接受的屬性是Object類型
            bd.setBeanClassName(className);
        }
    }
    return bd;
}

3.1.2 parseBeanDefinitionAttributes

跟蹤標記方法3.1.2ui

此方法在BeanDefinitionParserDelegate類中this

//3.1.2將bean標籤上的屬性設置到bean definition中
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);

/**
* Apply the attributes of the given bean element to the given bean * definition.
*
* 將bean標籤上的屬性設置到bean definition中
*/
public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
                                                            BeanDefinition containingBean, AbstractBeanDefinition bd) {
    
    //bean標籤上已經沒有singleton屬性了,用scope代替,因此出現就報錯
    if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
        error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
    }
    
    //若是設置了scope就拿其值
    else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
        bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
    }
    
    //此處containingBean爲空
    else if (containingBean != null) {
        
        // Take default from containing bean in case of an inner bean definition.
        // 若是是一個內部的bean definition,用包含的bean的default
        bd.setScope(containingBean.getScope());
    }
    
    //是否有abstract屬性
    if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
        bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
    }

    String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
    
    //lazyInit若是沒有設置則爲默認值,默認值用的代理類中defaults屬性,
    //也就是this.defaults
    if (DEFAULT_VALUE.equals(lazyInit)) {
        lazyInit = this.defaults.getLazyInit();
    }
    
    bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
    
    //默認值用的代理類中defaults屬性,不進行autowire
    String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
    bd.setAutowireMode(getAutowireMode(autowire));
    
    //默認不進行依賴檢查
    String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
    bd.setDependencyCheck(getDependencyCheck(dependencyCheck));
    
    //是否有depends-on屬性
    if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
        String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
        bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
    }
    
    //是否有autowire-candidate屬性,沒有或者爲默認則不設置
    String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
    if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
        String candidatePattern = this.defaults.getAutowireCandidates();
        if (candidatePattern != null) {
            String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
            bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
        }
    }
    else {
        bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
    }
    
    //是否有primary屬性
    if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
        bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
    }
    
    //是否有init-method屬性
    if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
        String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
        if (!"".equals(initMethodName)) {
            bd.setInitMethodName(initMethodName);
        }
    }
    else {
        
        //沒有init-method屬性,就拿代理類defaults屬性的
        if (this.defaults.getInitMethod() != null) {
            bd.setInitMethodName(this.defaults.getInitMethod());
            bd.setEnforceInitMethod(false);
        }
    }
    
    //是否有destroy-method屬性
    if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
        String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
        bd.setDestroyMethodName(destroyMethodName);
    }
    else {
        
        //沒有destroy-method屬性,就拿代理類defaults屬性的
        if (this.defaults.getDestroyMethod() != null) {
            bd.setDestroyMethodName(this.defaults.getDestroyMethod());
            bd.setEnforceDestroyMethod(false);
        }
    }
    
    //是否有factory-method屬性
    if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
        bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
    }
    
    //是否有factory-bean屬性
    if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
        bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
    }

    return bd;
}

這樣,bean標籤上的屬性也就解析完成了,對其屬性的描述無論設置了仍是沒有設置的,都有相應的值對應到bean definition中。接下來就要解析,bean標籤下的子標籤了。

3.1.3 parsePropertyElements

跟蹤3.1.3標記的方法

此方法在BeanDefinitionParserDelegate類中實現

//3.1.3解析Property的屬性設置到bean definition中
parsePropertyElements(ele, bd);


/**
* Parse property sub-elements of the given bean element.
* 解析bean標籤下property子標籤
*/
public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
    NodeList nl = beanEle.getChildNodes();
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
            
            //標籤名爲property才能進入,進入這個方法
            parsePropertyElement((Element) node, bd);
        }
    }
}


/**
* Parse a property element.
*/
public void parsePropertyElement(Element ele, BeanDefinition bd) {
    
    //拿到property標籤的name屬性
    String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
    if (!StringUtils.hasLength(propertyName)) {
        error("Tag 'property' must have a 'name' attribute", ele);
        return;
    }
    
    //解析的時候放入,解析完成彈出,這裏放入property標籤,
    //這裏面還存有bean父標籤,子標籤解析完成後先彈出
    this.parseState.push(new PropertyEntry(propertyName));
    try {
        
        //bean標籤下能夠有多個property,可是不能重複name屬性
        if (bd.getPropertyValues().contains(propertyName)) {
            error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
            return;
        }
        
        //進入這個方法,查看是怎麼解析property標籤屬性的
        Object val = parsePropertyValue(ele, bd, propertyName);
        
        //將name屬性和對應的value放入
        PropertyValue pv = new PropertyValue(propertyName, val);
        
        //解析property標籤的子標籤meta,
        //拿到meta的key和value屬性,設置到PropertyValue中
        parseMetaElements(ele, pv);
        
        //這裏沒有實現,爲null
        pv.setSource(extractSource(ele));
        
        //將PropertyValue添加到bean definition中
        bd.getPropertyValues().addPropertyValue(pv);
    }
    finally {
        
        //解析的時候放入,解析完成彈出,這裏放入property標籤
        this.parseState.pop();
    }
}




/**
* Get the value of a property element. May be a list etc.
* Also used for constructor arguments, "propertyName" being null in this case.
*
* 拿到property標籤的value值,多是list
* 也被constructor標籤使用,這種狀況propertyName爲null
*/
public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
   
    //若是propertyName爲null,則是constructor-arg標籤
    //不然爲property標籤
    String elementName = (propertyName != null) ?
        "<property> element for property '" + propertyName + "'" :
    "<constructor-arg> element";

    
    // Should only have one child element: ref, value, list, etc.
    //不論是哪一種標籤,下面都應該只有一個子標籤: ref, value, list等.
    NodeList nl = ele.getChildNodes();
    Element subElement = null;
    for (int i = 0; i < nl.getLength(); i++) {
        Node node = nl.item(i);
        if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
            !nodeNameEquals(node, META_ELEMENT)) {
            
            // Child element is what we're looking for.
            //除開description和meta標籤,子標籤最多隻能有一個
            if (subElement != null) {
                error(elementName + " must not contain more than one sub-element", ele);
            }
            else {
                subElement = (Element) node;
            }
        }
    }
    
    //看標籤屬性用的是value仍是ref
    boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
    boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
    
    //value和ref屬性不能同時存在,若是有子標籤,則value和ref都不能存在,不然報錯
    if ((hasRefAttribute && hasValueAttribute) ||
        ((hasRefAttribute || hasValueAttribute) && subElement != null)) {
        error(elementName +
              " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
    }
    
    //用的ref的狀況
    if (hasRefAttribute) {
        String refName = ele.getAttribute(REF_ATTRIBUTE);
        if (!StringUtils.hasText(refName)) {
            error(elementName + " contains empty 'ref' attribute", ele);
        }
        RuntimeBeanReference ref = new RuntimeBeanReference(refName);
        ref.setSource(extractSource(ele));
        return ref;
    }
    
    //用的value的狀況
    else if (hasValueAttribute) {
        TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
        valueHolder.setSource(extractSource(ele));
        return valueHolder;
    }
    
    //子標籤不爲null的狀況,進入這個方法查看
    else if (subElement != null) {
        return parsePropertySubElement(subElement, bd);
    }
    else {
        
        // Neither child element nor "ref" or "value" attribute found.
        //沒指定ref或者value或者子標籤,返回null
        error(elementName + " must specify a ref or value", ele);
        return null;
    }
}


/**
* 這個方法仍是在BeanDefinitionParserDelegate中
*/
public Object parsePropertySubElement(Element ele, BeanDefinition bd) {
    return parsePropertySubElement(ele, bd, null);
}

/**
* Parse a value, ref or collection sub-element of a property or
* constructor-arg element.
*
* 解析property或者constructor-arg標籤的子標籤,可能爲value, ref或者集合
*/
public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
   
    //若是這個子標籤不屬於beans的名稱空間,則走這個方法
    if (!isDefaultNamespace(ele)) {
        return parseNestedCustomElement(ele, bd);
    }
    
    //若是是bean子標籤,則走這個方法
    else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
        BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
        if (nestedBd != null) {
            nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
        }
        return nestedBd;
    }
    
    //若是是ref子標籤,則走這個方法
    else if (nodeNameEquals(ele, REF_ELEMENT)) {
        
        // A generic reference to any name of any bean.
        String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
        boolean toParent = false;
        if (!StringUtils.hasLength(refName)) {
            
            // A reference to the id of another bean in the same XML file.
            refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
            if (!StringUtils.hasLength(refName)) {
                
                // A reference to the id of another bean in a parent context.
                refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
                toParent = true;
                if (!StringUtils.hasLength(refName)) {
                    error("'bean', 'local' or 'parent' is required for <ref> element", ele);
                    return null;
                }
            }
        }
        if (!StringUtils.hasText(refName)) {
            error("<ref> element contains empty target attribute", ele);
            return null;
        }
        RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
        ref.setSource(extractSource(ele));
        return ref;
    }
    
    //若是是idref子標籤,則走這個方法
    else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
        return parseIdRefElement(ele);
    }
    
    //若是是value子標籤,則走這個方法
    else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
        
        //以這個方法做爲演示,其餘的方法都是大同小異,進入。
        return parseValueElement(ele, defaultValueType);
    }
    
    //若是是null子標籤,則走這個方法
    else if (nodeNameEquals(ele, NULL_ELEMENT)) {
        
        // It's a distinguished null value. Let's wrap it in a TypedStringValue
        // object in order to preserve the source location.
        TypedStringValue nullHolder = new TypedStringValue(null);
        nullHolder.setSource(extractSource(ele));
        return nullHolder;
    }
    
    //若是是array子標籤,則走這個方法
    else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
        return parseArrayElement(ele, bd);
    }
    
    //若是是list子標籤,則走這個方法
    else if (nodeNameEquals(ele, LIST_ELEMENT)) {
        return parseListElement(ele, bd);
    }
    
    //若是是set子標籤,則走這個方法
    else if (nodeNameEquals(ele, SET_ELEMENT)) {
        return parseSetElement(ele, bd);
    }
    
    //若是是map子標籤,則走這個方法
    else if (nodeNameEquals(ele, MAP_ELEMENT)) {
        return parseMapElement(ele, bd);
    }
    
    //若是是props子標籤,則走這個方法
    else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
        return parsePropsElement(ele);
    }
    
    //不然返回null,報錯
    else {
        error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
        return null;
    }
}


/**
* Return a typed String value Object for the given value element.
*
* 經過指定的value標籤,返回指定的字符串value對象
*/
public Object parseValueElement(Element ele, String defaultTypeName) {
    
    // It's a literal value.
    //拿到value中的文本,包括回車、tab製表符、空格
    String value = DomUtils.getTextValue(ele);
    
    //有無type屬性
    String specifiedTypeName = ele.getAttribute(TYPE_ATTRIBUTE);
    String typeName = specifiedTypeName;
    if (!StringUtils.hasText(typeName)) {
        
        //沒有就用入參defaultTypeName
        typeName = defaultTypeName;
    }
    try {
        TypedStringValue typedValue = buildTypedStringValue(value, typeName);
        
        //這裏設置爲空
        typedValue.setSource(extractSource(ele));
        
        //這裏爲空字符串
        typedValue.setSpecifiedTypeName(specifiedTypeName);
        
        //返回typedValue
        return typedValue;
    }
    catch (ClassNotFoundException ex) {
        error("Type class [" + typeName + "] not found for <value> element", ele, ex);
        return value;
    }
}

3.2 decorateBeanDefinitionIfRequired

在生成了BeanDefinitionHolder之後,若是須要的話應該經過代理類對bean definition進行渲染。

跟蹤標記3.2的方法

該方法的實如今BeanDefinitionParserDelegate類中

//3.2若是有要求的話渲染beanDefinition
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);


public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {
    return decorateBeanDefinitionIfRequired(ele, definitionHolder, null);
}


public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
    Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) {

    BeanDefinitionHolder finalDefinition = definitionHolder;

    // Decorate based on custom attributes first.
    // 首先基於自定義屬性進行渲染
    // 也就是bean標籤上的屬性,也就是node
    // 只有當這個node不屬於名稱空間beans纔會進行渲染,這裏就不進去看了
    NamedNodeMap attributes = ele.getAttributes();
    for (int i = 0; i < attributes.getLength(); i++) {
        Node node = attributes.item(i);
        finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
    }

    // Decorate based on custom nested elements.
    // 而後根據標籤內嵌套的子標籤進行渲染
    // 這裏是不屬於名稱空間beans的子標籤纔會進行渲染
    NodeList children = ele.getChildNodes();
    for (int i = 0; i < children.getLength(); i++) {
        Node node = children.item(i);
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
        }
    }
    return finalDefinition;
}

3.3 registerBeanDefinition

最終將完成的bean definition註冊到工廠中

跟蹤標記3.3的方法

//3.3註冊最終被渲染的實例到工廠中
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

/**
* Register the given bean definition with the given bean factory.
*
* 註冊bean definition
*/
public static void registerBeanDefinition(
    BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    throws BeanDefinitionStoreException {

    // Register bean definition under primary name.
    
    // 3.3.1註冊bean definition的beanName
    // 好比tk.mybatis.spring.mapper.MapperScannerConfigurer#0
    String beanName = definitionHolder.getBeanName();
    
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

    // Register aliases for bean name, if any.
    
    // 若是有別名的話,爲bean name註冊別名
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
        for (String alias : aliases) {
            
            //3.3.2註冊別名
            registry.registerAlias(beanName, alias);
        }
    }
}

3.3.1 registerBeanDefinition

跟蹤標記3.3.1的方法

// 3.3.1註冊bean definition的beanName
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
    throws BeanDefinitionStoreException {

    Assert.hasText(beanName, "Bean name must not be empty");
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");

    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {
            
            //作一個驗證,靜態工廠方法和覆蓋方法不能組合使用
            //若是bean definition中的beanClass屬性不是String類型而是Class類型
            //那麼就要驗證和準備這個bean定義的覆蓋方法,檢查指定名稱的方法是否存在
            ((AbstractBeanDefinition) beanDefinition).validate();
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                                                   "Validation of bean definition failed", ex);
        }
    }

    BeanDefinition oldBeanDefinition;
    
    //查看beanName是否已經被註冊在工廠的beanDefinitionMap屬性中
    oldBeanDefinition = this.beanDefinitionMap.get(beanName);
    
    //已經被註冊走這個方法,這裏不查看
    if (oldBeanDefinition != null) {
        if (!isAllowBeanDefinitionOverriding()) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                                                   "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
                                                   "': There is already [" + oldBeanDefinition + "] bound.");
        }
        else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
            
            // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
            if (this.logger.isWarnEnabled()) {
                this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                                 "' with a framework-generated bean definition: replacing [" +
                                 oldBeanDefinition + "] with [" + beanDefinition + "]");
            }
        }
        else if (!beanDefinition.equals(oldBeanDefinition)) {
            if (this.logger.isInfoEnabled()) {
                this.logger.info("Overriding bean definition for bean '" + beanName +
                                 "' with a different definition: replacing [" + oldBeanDefinition +
                                 "] with [" + beanDefinition + "]");
            }
        }
        else {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Overriding bean definition for bean '" + beanName +
                                  "' with an equivalent definition: replacing [" + oldBeanDefinition +
                                  "] with [" + beanDefinition + "]");
            }
        }
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    else {
        
        //這裏面表明beanName尚未被註冊
        //而後根據階段不一樣又有一層判斷
        if (hasBeanCreationStarted()) {
            
            //這個階段是bean已經開始建立
            // Cannot modify startup-time collection elements anymore (for stable iteration)
            synchronized (this.beanDefinitionMap) {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                if (this.manualSingletonNames.contains(beanName)) {
                    Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
                    updatedSingletons.remove(beanName);
                    this.manualSingletonNames = updatedSingletons;
                }
            }
        }
        else {
            
            // Still in startup registration phase
            
            // 仍然處於啓動時的註冊階段
            // 因此這裏走這個方法
            //beanDefinitionMap是工廠的一個屬性,ConcurrentHashMap類型
            //他保存全部解析好的bean Definition的名稱和實例的映射
            this.beanDefinitionMap.put(beanName, beanDefinition);
            
            //beanName也單獨使用了一個ArrayList來保存,方便遍歷
            this.beanDefinitionNames.add(beanName);
            
            //若是該bean definition是手動註冊的,還要從manualSingletonNames中
            //移除bean definition的beanName,還要從manualSingletonNames中是LinkedHashSet
            this.manualSingletonNames.remove(beanName);
        }
        this.frozenBeanDefinitionNames = null;
    }
    
    //這裏跳過
    if (oldBeanDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
    }
}

3.3.2 registerAlias

跟蹤3.3.2方法

//3.3.2註冊別名
registry.registerAlias(beanName, alias);

@Override
public void registerAlias(String name, String alias) {
    Assert.hasText(name, "'name' must not be empty");
    Assert.hasText(alias, "'alias' must not be empty");
    if (alias.equals(name)) {
        
        //移除別名中的beanName
        //aliasMap是ConcurrentHashMap類型,保存別名和beanName的映射
        this.aliasMap.remove(alias);
    }
    else {
        String registeredName = this.aliasMap.get(alias);
        
        //若是別名對應beanName已經被註冊,則不須要再註冊一次
        //別名不容許被覆蓋
        if (registeredName != null) {
            if (registeredName.equals(name)) {
                
                // An existing alias - no need to re-register
                return;
            }
            if (!allowAliasOverriding()) {
                throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
                                                name + "': It is already registered for name '" + registeredName + "'.");
            }
        }
        
        //再檢查一遍,aliasMap中不能已經存在name和alias
        checkForAliasCircle(name, alias);
        
        //工廠的aliasMap屬性保存別名,那麼alias已被註冊
        this.aliasMap.put(alias, name);
    }
}

這樣,spring配置文件中爲bean標籤的解析和加載,也就跟蹤完了。

而後再看下非默認名稱空間的標籤的解析和加載。

由於字數超過了限制,因此分紅了三篇,點擊下篇繼續閱讀
https://www.jianshu.com/p/6e0f6fd1cbbd

總結

3

  • 走解析默認元素的方法。根據beans名稱空間下,不一樣的標籤有不一樣的子方法,對於<bean>標籤來講,主要分爲三步:
    • 3.1 經過代理 delegate 解析 bean 元素生成 BeanDefinitionHolder
    • 若是有必要的話,利用非默認名稱空間的屬性和子標籤,渲染 BeanDefinitionHolder 中的 BeanDefinition
    • 註冊最終被渲染的實例到工廠中。分兩步,一步註冊 BeanDefinition ,其實就是將 beanName 和 BeanDefinition 放入 beanDefinitionMap 中,beanName 放入 beanDefinitionNames中;一步註冊別名,將 alias、name放入到 aliasMap 中

——————————————————————————————————

  • 3.1
  • 獲取元素上的 id、name 屬性,id 做爲 beanName,name 做爲別名。若是沒有指定 id,取 name 的一個值做爲 beanName,別名中移除該值。
  • 解析元素生成 BeanDefinition
  • 若是屬性沒有指定 id 也沒有指定 name,利用 beanDefinition 生成一個 beanName。當這個bean是內部bean,類的全限定名加#號再加哈希值;當是頂層bean,類的全限定名加#號再從0開始加數字,id已被註冊數字就增1,直到惟一。有了 beanName,再以類的全限定名做爲別名。
  • 利用 BeanDefinition ,beanName ,別名,生成 BeanDefinitionHolder 並返回

——————————————————————————————————

  • 解析元素生成 BeanDefinition
    • 根據 bean 元素中的 class 屬性和 parent 屬性建立 BeanDefinition
    • 將 bean 標籤上的屬性設置到 BeanDefinition 中,一些未明確指定的屬性採用代理 delegate 中的 defaults 值
    • 解析 bean 標籤下的子標籤,如 Property 、constructor-arg 等,將其鍵值對添加到 BeanDefinition 中
    • 返回 BeanDefinition
相關文章
相關標籤/搜索