Spring 源碼分析之默認(rèn)標(biāo)簽解析

上一節(jié) 我們說到 IOC容器的基本實(shí)現(xiàn),分析到解析標(biāo)簽 :如以下代碼

 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) { //判斷是否使用了默認(rèn)的命名空間 如果是則,執(zhí)行一下代碼 如果不是 執(zhí)行自定義標(biāo)簽的解析 
            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)) {
                        this.parseDefaultElement(ele, delegate);//執(zhí)行默認(rèn)標(biāo)簽的解析
                    } else {
                        delegate.parseCustomElement(ele);//執(zhí)行自定義標(biāo)簽的解析 
                    }
                }
            }
        } else {
            delegate.parseCustomElement(root);//執(zhí)行自定義標(biāo)簽的解析 
        }
    }

現(xiàn)在我們就先分析下 執(zhí)行默認(rèn)標(biāo)簽的解析:點(diǎn)入parseDefaultElement(ele, delegate)方法

 private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        if (delegate.nodeNameEquals(ele, "import")) { 
            this.importBeanDefinitionResource(ele);//解析import 標(biāo)簽
        } else if (delegate.nodeNameEquals(ele, "alias")) {
            this.processAliasRegistration(ele);//解析alias 標(biāo)簽
        } else if (delegate.nodeNameEquals(ele, "bean")) {
            this.processBeanDefinition(ele, delegate);//解析bean標(biāo)簽
        } else if (delegate.nodeNameEquals(ele, "beans")) {
            this.doRegisterBeanDefinitions(ele);//解析beans標(biāo)簽
        }
    }

如以上我們分析了 Spring解析4種標(biāo)簽:import標(biāo)簽, alias標(biāo)簽狱窘, bean標(biāo)簽和beans標(biāo)簽摔吏,這里我們重點(diǎn)分析一下 如何解析bean標(biāo)簽

解析bean標(biāo)簽
 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);//委托delegate解析
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);//如果beanHolder 不為空 ,則進(jìn)行裝配
            try {
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());//開始注冊bean
            } catch (BeanDefinitionStoreException var5) {
                this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
            }
            this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));//通知監(jiān)聽器以及边酒,這個(gè)bean已經(jīng)加載完成
        }
    }

1.委托delegate.parseBeanDefinitionElement()方法進(jìn)行解析赂摆,將解析后的值封裝到BeanDefinitionHolder 的實(shí)例bdHolder中挟憔,此時(shí)我們的BeanDefintionHolder以及有配置文件中的各個(gè)屬性了钟些,如Class name id之類的屬性
2.如果bean不為空的情況下,若存在bean標(biāo)簽的子節(jié)點(diǎn)再有在定義屬性绊谭,還需要對bean標(biāo)簽再次進(jìn)行解析
3.解析完成 之后的注冊交給了registerBeanDefinition()方法

提取bean信息
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
    String id = ele.getAttribute("id");//提取id
    String nameAttr = ele.getAttribute("name");//提取name
    List<String> aliases = new ArrayList();
    if (StringUtils.hasLength(nameAttr)) {
        String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
        aliases.addAll(Arrays.asList(nameArr));
    }

    String beanName = id;
    if (!StringUtils.hasText(id) && !aliases.isEmpty()) {
        beanName = (String)aliases.remove(0);
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
        }
    }

    if (containingBean == null) {
        this.checkNameUniqueness(beanName, aliases, ele);
    }

    AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);//提取bean標(biāo)簽的其他屬性 進(jìn)一步封裝到GenericbeanDefaintion中
    if (beanDefinition != null) {
        if (!StringUtils.hasText(beanName)) {
            try {
                if (containingBean != null) {
                    beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
                } else {
                    beanName = this.readerContext.generateBeanName(beanDefinition);
                    String beanClassName = beanDefinition.getBeanClassName();
                    if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                        aliases.add(beanClassName);
                    }
                }

                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
                }
            } catch (Exception var9) {
                this.error(var9.getMessage(), ele);
                return null;
            }
        }
        String[] aliasesArray = StringUtils.toStringArray(aliases);
        return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    } else {
        return null;
    }
}

1.提取id和name的屬性
2.進(jìn)一步解析其他屬性 封裝到GenericBeanDefinition類型的實(shí)例中
3.檢測beanName,如果沒有beanName,則默認(rèn)使用Bean為他生成BeanName
4.將解析出來的信息封裝到BeanDefinitionHolder的實(shí)例中

解析其他標(biāo)簽的屬性
  public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {
        this.parseState.push(new BeanEntry(beanName));
        String className = null;
        if (ele.hasAttribute("class")) { //解析Class屬性
            className = ele.getAttribute("class").trim();
        }

        try {
            String parent = null;
            if (ele.hasAttribute("parent")) {//解析parent屬性
                parent = ele.getAttribute("parent");
            }

            AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);//創(chuàng)建用與承載屬性 AbstractBeanDefintion 類型的GenericBeanDefinition實(shí)例
            //硬編碼解析默認(rèn)bean的各個(gè)屬性
            this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
          //解析Description
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
            //解析meta
            this.parseMetaElements(ele, bd);
            //解析LookUp-method
            this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            //解析Replaced-method
            this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            //解析構(gòu)造函數(shù)參數(shù)
            this.parseConstructorArgElements(ele, bd);
            //解析Property元素
            this.parsePropertyElements(ele, bd);
            //解析Qualifier子元素
            this.parseQualifierElements(ele, bd);
            bd.setResource(this.readerContext.getResource());
            bd.setSource(this.extractSource(ele));
            AbstractBeanDefinition var7 = bd;
            return var7;
        } catch (ClassNotFoundException var13) {
            this.error("Bean class [" + className + "] not found", ele, var13);
        } catch (NoClassDefFoundError var14) {
            this.error("Class that bean class [" + className + "] depends on not found", ele, var14);
        } catch (Throwable var15) {
            this.error("Unexpected failure during bean definition parsing", ele, var15);
        } finally {
            this.parseState.pop();
        }
        return null;
    }
創(chuàng)建用于屬性承載的BeanDefinition

beanDefinition 是一個(gè)接口 用三種實(shí)現(xiàn) RootBeanDefinition,ChildBeanDefinition以及GenericBeanDefinition 這三種均實(shí)現(xiàn)了AbstractBeanDefinitionBean 它們之間的關(guān)系如下圖:


繼承關(guān)系.png

由此可見 首先就是要?jiǎng)?chuàng)建 承載屬性的實(shí)例政恍,也就是創(chuàng)建GenericBeanDefintion 類型的實(shí)例

 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) {
                bd.setBeanClass(ClassUtils.forName(className, classLoader));
            } else {
                bd.setBeanClassName(className); //記錄ClassName
            }
        }
        return bd;
    }

創(chuàng)建完用于屬性承載的BeanDefinition 接下來就是 解析各種屬性了

解析各種屬性

this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
是對Element所有元素進(jìn)行解析

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) {
        if (ele.hasAttribute("scope")) { //解析Scope屬性
            bd.setScope(ele.getAttribute("scope"));
        } else if (containingBean != null) {
            bd.setScope(containingBean.getScope());
        }

        if (ele.hasAttribute("abstract")) {//解析abstract屬性
            bd.setAbstract("true".equals(ele.getAttribute("abstract")));
        }

        String lazyInit = ele.getAttribute("lazy-init");
        if ("default".equals(lazyInit)) { //解析lazy-init 屬性
            lazyInit = this.defaults.getLazyInit();
        }

        bd.setLazyInit("true".equals(lazyInit));
        String autowire = ele.getAttribute("autowire");//解析autowire屬性
        bd.setAutowireMode(this.getAutowireMode(autowire));
        String dependencyCheck = ele.getAttribute("dependency-check")//解析dependency-check屬性;
        bd.setDependencyCheck(this.getDependencyCheck(dependencyCheck));
        String autowireCandidate;
        if (ele.hasAttribute("depends-on")) {//解析denpends-on屬性
            autowireCandidate = ele.getAttribute("depends-on");
            bd.setDependsOn(StringUtils.tokenizeToStringArray(autowireCandidate, ",; "));
        }
        //解析autowire-candidate 屬性
        autowireCandidate = ele.getAttribute("autowire-candidate");
        String destroyMethodName;
        if (!"".equals(autowireCandidate) && !"default".equals(autowireCandidate)) {
            bd.setAutowireCandidate("true".equals(autowireCandidate));
        } else {
            destroyMethodName = this.defaults.getAutowireCandidates();
            if (destroyMethodName != null) {
                String[] patterns = StringUtils.commaDelimitedListToStringArray(destroyMethodName);
                bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
            }
        }
       //解析primary 屬性
        if (ele.hasAttribute("primary")) {
            bd.setPrimary("true".equals(ele.getAttribute("primary")));
        }
        //解析init-method 屬性
        if (ele.hasAttribute("init-method")) {
            destroyMethodName = ele.getAttribute("init-method");
            if (!"".equals(destroyMethodName)) {
                bd.setInitMethodName(destroyMethodName);
            }
        } else if (this.defaults.getInitMethod() != null) {
            bd.setInitMethodName(this.defaults.getInitMethod());
            bd.setEnforceInitMethod(false);
        }
        //解析destroy-method 屬性
        if (ele.hasAttribute("destroy-method")) {
            destroyMethodName = ele.getAttribute("destroy-method");
            if (!"".equals(destroyMethodName)) {
                bd.setDestroyMethodName(destroyMethodName);
            }
        } else if (this.defaults.getDestroyMethod() != null) {
            bd.setDestroyMethodName(this.defaults.getDestroyMethod());
            bd.setEnforceDestroyMethod(false);
        }
          //解析factory-method屬性
        if (ele.hasAttribute("factory-method")) {
            bd.setFactoryMethodName(ele.getAttribute("factory-method"));
        }
        //解析factory-bean屬性
        if (ele.hasAttribute("factory-bean")) {
            bd.setFactoryBeanName(ele.getAttribute("factory-bean"));
        }
        return bd;
    }

我們清楚的看見了 Spring對各個(gè)標(biāo)簽的解析 包括 我們經(jīng)常用到的,不經(jīng)常用的都進(jìn)行了解析达传,解析來就讓我們分析Spring 是如何 解析各個(gè)元素的篙耗。


image.png
解析Meta子標(biāo)簽
<bean id ="myTestMeta" class="com.zhh.MyTestMeta">
    <meta key="testStr" value="testValue"/>
</bean>
 public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
        NodeList nl = ele.getChildNodes();
        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
         //判斷當(dāng)前節(jié)點(diǎn)是否是Meta
            if (this.isCandidateElement(node) && this.nodeNameEquals(node, "meta")) {
                Element metaElement = (Element)node;
                String key = metaElement.getAttribute("key");
                String value = metaElement.getAttribute("value");
                //使用BeanMetadataAttribute  封裝Meta 的Key和Value
                BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
                attribute.setSource(this.extractSource(metaElement));
                attributeAccessor.addMetadataAttribute(attribute);
            }
        }
    }
解析子標(biāo)簽LookUp-method

或許LookUp-method 子標(biāo)簽并不常用 我們通過一個(gè)列子來說明

public Class User{
    public void showme(){
      System.out.println("I am User");
  }
}
public Class Teacher Extends User{
  public void showme(){
  System.out.println("i am teaacher");
}
}
//創(chuàng)建調(diào)用方法
public abstract class GetBeanTest{
    public void showme(){
      this.getBean.showme();  
}
public abstract User getBean();
}
//xml配置
<bean id="getBeanTest" class="com.zhh.GetBeanTest">
  <lookup-method name="getBean" bean="teacher"/>
</bean>
<bean id="teacher" class="com.zhh.Teacher"/>
//運(yùn)行結(jié)果
i an Teacher

抽象方法沒有被實(shí)現(xiàn) 怎么會被調(diào)用呢 我們看配置 完成的功能是,動(dòng)態(tài)的將teacher所代表的的bean 作為getBean的返回值 宪赶。我們看是如何解析的

  public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
        NodeList nl = beanEle.getChildNodes();
        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
            //當(dāng)且僅當(dāng) 當(dāng)前子標(biāo)簽lookup-method 是在進(jìn)行解析
            if (this.isCandidateElement(node) && this.nodeNameEquals(node, "lookup-method")) {
                Element ele = (Element)node;
                String methodName = ele.getAttribute("name");
                String beanRef = ele.getAttribute("bean");
                //使用lookupOverride 封裝name和bean元素
                LookupOverride override = new LookupOverride(methodName, beanRef);
                override.setSource(this.extractSource(ele));
                overrides.addOverride(override);
            }
        }
    }
解析replaced-method 子標(biāo)簽

如果說 lookup-method 中的屬性bean 所代表的的bean 作為屬性name 的返回值宗弯。那么replaced-method 可以動(dòng)態(tài)的改變 原有方法的邏輯

   public class TestChangeMethod(){
    public void changeMethod(){
      Sytem.out.println("change me");
  }
  }
//如果有一天 在上線后 要改變原有的邏輯怎么辦?
pulic class TestMethodReplacer implements org.springframework.beans.factory.support.MethodReplacer{
    public Object reimplement(Object obj,Method method,Object []){
    System.out.println("我替換了原來的方法.....");
      return null搂妻;
 }
}
//xml 這樣配置
<bean id="testChangeMethod" class="test.replacemethod.TestChangeMethod">
  <replaced-method name="changeMe" replace="replace">
</bean>
<bean id ="replace" class="com.zhh.TestMethodReplacer"/>

解析來我們看是如何解析的 replace-method標(biāo)簽的

  public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) {
        NodeList nl = beanEle.getChildNodes();

        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
            //判斷當(dāng)前標(biāo)簽是否是replaced-method 字標(biāo)簽
            if (this.isCandidateElement(node) && this.nodeNameEquals(node, "replaced-method")) {
                Element replacedMethodEle = (Element)node;
                 //提取要替換舊的方法的名稱
                String name = replacedMethodEle.getAttribute("name");
                //提取對應(yīng)的新的替換方法
                String callback = replacedMethodEle.getAttribute("replacer");
                //創(chuàng)建用于封裝name和replace 的實(shí)例bean ReplaceOverride
                ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
                List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, "arg-type");
                Iterator var11 = argTypeEles.iterator();

                while(var11.hasNext()) {
                    Element argTypeEle = (Element)var11.next();
                    String match = argTypeEle.getAttribute("match");
                    match = StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle);
                    if (StringUtils.hasText(match)) {
                        replaceOverride.addTypeIdentifier(match);
                    }
                }
                replaceOverride.setSource(this.extractSource(replacedMethodEle));
                overrides.addOverride(replaceOverride);
            }
        }
    }
解析子元素Conctructor-arg

Conctructor-age 字標(biāo)簽是非常常用的

<bean id ="helloBean" class="com.zhh.hellobean">
    <conctructor-arg index="0">
         <value>aaaa</value> 
    </conctructor-arg>
</bean>

以上是conctructor-arg最基本的用法 那么我們看是如何解析的蒙保?

   public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
        String indexAttr = ele.getAttribute("index");//獲取index 屬性
        String typeAttr = ele.getAttribute("type");//獲取type屬性
        String nameAttr = ele.getAttribute("name");//獲取name屬性
        if (StringUtils.hasLength(indexAttr)) { //判斷是否有index屬性
            try {
                int index = Integer.parseInt(indexAttr);
                if (index < 0) {
                    this.error("'index' cannot be lower than 0", ele);
                } else {
                    try {
                        this.parseState.push(new ConstructorArgumentEntry(index));
                        Object value = this.parsePropertyValue(ele, bd, (String)null);
                        ValueHolder valueHolder = new ValueHolder(value);
                        if (StringUtils.hasLength(typeAttr)) {
                            valueHolder.setType(typeAttr);
                        }

                        if (StringUtils.hasLength(nameAttr)) {
                            valueHolder.setName(nameAttr);
                        }

                        valueHolder.setSource(this.extractSource(ele));
                        if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
                            this.error("Ambiguous constructor-arg entries for index " + index, ele);
                        } else {
                            bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
                        }
                    } finally {
                        this.parseState.pop();
                    }
                }
            } catch (NumberFormatException var19) {
                this.error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
            }
        } else {
              //沒有index屬性自動(dòng)尋找 
            try {
                this.parseState.push(new ConstructorArgumentEntry());
                Object value = this.parsePropertyValue(ele, bd, (String)null);
                ValueHolder valueHolder = new ValueHolder(value);
                if (StringUtils.hasLength(typeAttr)) {
                    valueHolder.setType(typeAttr);
                }

                if (StringUtils.hasLength(nameAttr)) {
                    valueHolder.setName(nameAttr);
                }

                valueHolder.setSource(this.extractSource(ele));
                bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
            } finally {
                this.parseState.pop();
            }
        }

    }

1.判斷是否有index屬性 ,有 則步驟如下
1.1 解析constructor-arg的子元素
1.2 使用ConstructorArgmentValues.ValueHolder封裝 解析出來的元素
1.3 將 封裝的元素添加到BeanDefinition中的ContrucotrAgrmentValues的IndexedArgumentValue元素中
2.沒有則步驟如下
1.1 解析constructor-arg的子元素
1.2 使用ConstructorArgmentValues.ValueHolder封裝 解析出來的元素
1.3 將 封裝的元素添加到BeanDefinition中的ContrucotrAgrmentValues的GenericArgumentValue元素中

沒有Index和 有index 關(guān)鍵在于封裝的位置不同 有Index屬性封裝在IndexedArgumentValue 沒有封裝在 GenericArgumentValue中
那么我們分析一下 parsePropertyValue()這個(gè)方法

  public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
        String elementName = propertyName != null ? "<property> element for property '" + propertyName + "'" : "<constructor-arg> element";
        NodeList nl = ele.getChildNodes();
        Element subElement = null;
        //一個(gè)屬性只能對應(yīng)一種類型
        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
            //對description和meta 不做處理
            if (node instanceof Element && !this.nodeNameEquals(node, "description") && !this.nodeNameEquals(node, "meta")) {
                if (subElement != null) {
                    this.error(elementName + " must not contain more than one sub-element", ele);
                } else {
                    subElement = (Element)node;
                }
            }
        }
        //提取ref屬性
        boolean hasRefAttribute = ele.hasAttribute("ref");
        boolean hasValueAttribute = ele.hasAttribute("value");//提取value屬性
        if (hasRefAttribute && hasValueAttribute || (hasRefAttribute || hasValueAttribute) && subElement != null) {
           //Contructor-age上不存在
          //既有ref屬性又有value屬性  存在ref又有子元素或者value屬性又有子元素
            this.error(elementName + " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
        }
        //對ref的處理 用RuntimeBeanReference 封裝
        if (hasRefAttribute) {
            String refName = ele.getAttribute("ref");
            if (!StringUtils.hasText(refName)) {
                this.error(elementName + " contains empty 'ref' attribute", ele);
            }

            RuntimeBeanReference ref = new RuntimeBeanReference(refName);
            ref.setSource(this.extractSource(ele));
            return ref;
        } else if (hasValueAttribute) {//對value屬性的處理 用 TypedStringValue封裝
            TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute("value"));
            valueHolder.setSource(this.extractSource(ele));
            return valueHolder;
        } else if (subElement != null) {//解析子元素
            return this.parsePropertySubElement(subElement, bd);
        } else {
            this.error(elementName + " must specify a ref or value", ele);
            return null;
        }
    }

上述步驟可以分為:
1.不提取description和meta
2.提取ref和value屬性 同時(shí)判斷不能同時(shí)存在ref屬性和value屬性
3.對ref屬性進(jìn)行提取 用RuntimeBeanReference封裝
4.對value屬性進(jìn)行提取 用 TypedStringValue封裝
5.對子元素進(jìn)行解析

   <constructor-arg>
       <map>
             <entry key="key" value="value"/>
       </map>
   </constructor-arg>

則對子元素進(jìn)行提取欲主,則解析過程如下

   public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
        if (!this.isDefaultNamespace((Node)ele)) {
            return this.parseNestedCustomElement(ele, bd);
        } else if (this.nodeNameEquals(ele, "bean")) {
            BeanDefinitionHolder nestedBd = this.parseBeanDefinitionElement(ele, bd);
            if (nestedBd != null) {
                nestedBd = this.decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
            }

            return nestedBd;
        } else if (this.nodeNameEquals(ele, "ref")) {
            String refName = ele.getAttribute("bean");
            boolean toParent = false;
            if (!StringUtils.hasLength(refName)) {
                refName = ele.getAttribute("local");//解析local
                if (!StringUtils.hasLength(refName)) {
                    refName = ele.getAttribute("parent"); //解析parent
                    toParent = true;
                    if (!StringUtils.hasLength(refName)) {
                        this.error("'bean', 'local' or 'parent' is required for <ref> element", ele);
                        return null;
                    }
                }
            }

            if (!StringUtils.hasText(refName)) {
                this.error("<ref> element contains empty target attribute", ele);
                return null;
            } else {
                RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
                ref.setSource(this.extractSource(ele));
                return ref;
            }
        } else if (this.nodeNameEquals(ele, "idref")) {//對idref元素進(jìn)行解析
            return this.parseIdRefElement(ele);
        } else if (this.nodeNameEquals(ele, "value")) {//對Value進(jìn)行解析
            return this.parseValueElement(ele, defaultValueType);
        } else if (this.nodeNameEquals(ele, "null")) {//對null 進(jìn)行解析
            TypedStringValue nullHolder = new TypedStringValue((String)null);
            nullHolder.setSource(this.extractSource(ele));
            return nullHolder;
        } else if (this.nodeNameEquals(ele, "array")) {//對array進(jìn)行解析
            return this.parseArrayElement(ele, bd);
        } else if (this.nodeNameEquals(ele, "list")) {//對list進(jìn)行解析
            return this.parseListElement(ele, bd);
        } else if (this.nodeNameEquals(ele, "set")) {/對set進(jìn)行解析
            return this.parseSetElement(ele, bd);
        } else if (this.nodeNameEquals(ele, "map")) {//對map進(jìn)行解析
            return this.parseMapElement(ele, bd);
        } else if (this.nodeNameEquals(ele, "props")) {//對props進(jìn)行解析
            return this.parsePropsElement(ele);
        } else {
            this.error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
            return null;
        }
    }
解析子標(biāo)簽property
public void parsePropertyElement(Element ele, BeanDefinition bd) {
        String propertyName = ele.getAttribute("name");//解析屬性name的值
        if (!StringUtils.hasLength(propertyName)) {
            this.error("Tag 'property' must have a 'name' attribute", ele);
        } else {
            this.parseState.push(new PropertyEntry(propertyName));

            try {
                if (!bd.getPropertyValues().contains(propertyName)) {
                    Object val = this.parsePropertyValue(ele, bd, propertyName);
                    PropertyValue pv = new PropertyValue(propertyName, val);//將返回出來的值用PropertyValue 進(jìn)行封裝
                    this.parseMetaElements(ele, pv);
                    pv.setSource(this.extractSource(ele));
                    bd.getPropertyValues().addPropertyValue(pv);
                    return;
                }

                this.error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
            } finally {
                this.parseState.pop();
            }

        }
    }
解析字標(biāo)簽Qualifier

對Qualifer 的使用如下

    <bean id="myTest" class="com.zhh.MyTestBean">
          <qualifier type="org.springframeWork.beans.annotaion.Qualifier" value="qf">
    </bean>

具體解析如下

 public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {
        String typeName = ele.getAttribute("type");//對type進(jìn)行提取
        if (!StringUtils.hasLength(typeName)) {
            this.error("Tag 'qualifier' must have a 'type' attribute", ele);
        } else {
            this.parseState.push(new QualifierEntry(typeName));

            try {
                AutowireCandidateQualifier qualifier = new AutowireCandidateQualifier(typeName);//創(chuàng)建用于封裝type 和 value的AutowireCandidateQualifier
                qualifier.setSource(this.extractSource(ele));
                String value = ele.getAttribute("value");
                if (StringUtils.hasLength(value)) {
                    qualifier.setAttribute(AutowireCandidateQualifier.VALUE_KEY, value);
                }

                NodeList nl = ele.getChildNodes();

                for(int i = 0; i < nl.getLength(); ++i) {
                    Node node = nl.item(i);
                    if (this.isCandidateElement(node) && this.nodeNameEquals(node, "attribute")) {
                        Element attributeEle = (Element)node;
                        String attributeName = attributeEle.getAttribute("key");
                        String attributeValue = attributeEle.getAttribute("value");
                        if (!StringUtils.hasLength(attributeName) || !StringUtils.hasLength(attributeValue)) {
                            this.error("Qualifier 'attribute' tag must have a 'name' and 'value'", attributeEle);
                            return;
                        }

                        BeanMetadataAttribute attribute = new BeanMetadataAttribute(attributeName, attributeValue);
                        attribute.setSource(this.extractSource(attributeEle));
                        qualifier.addMetadataAttribute(attribute);
                    }
                }

                bd.addQualifier(qualifier);
            } finally {
                this.parseState.pop();
            }
        }
    }

到這里我們也分析了默認(rèn)標(biāo)簽的解析與提取過程邓厕,當(dāng)前我們分析了
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);這句話
那么我們接著分析 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
其實(shí)程序執(zhí)行到這一步 Spring默認(rèn)的標(biāo)簽以及執(zhí)行完了 而這一步是對自定義標(biāo)簽進(jìn)行解析

注冊解析的BeanDefinition

 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
          //使用beanName作為唯一標(biāo)識
        String beanName = definitionHolder.getBeanName();
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());//通過BeanName注冊
        //獲取所有的別名 
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            String[] var4 = aliases;
            int var5 = aliases.length;
            for(int var6 = 0; var6 < var5; ++var6) {
                String aliase = var4[var6];
                registry.registerAlias(beanName, aliase);//通過BeanName注冊別名
            }
        }
    }

從上面我們可以看出,解析的beanDefinition都會注冊到BeanDefinitionRegistry類型的實(shí)例registry中

1.通過BeanName注冊BeanDefinition

 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 {
                ((AbstractBeanDefinition)beanDefinition).validate();
            } catch (BeanDefinitionValidationException var7) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var7);
            }
        }

        Map var3 = this.beanDefinitionMap;
         //因?yàn)閎eanDefinitionMap是全局變量 會存在并發(fā)
        synchronized(this.beanDefinitionMap) {
            //根據(jù)beanName獲取bean 
            BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
            if (oldBeanDefinition != null) { //如果根據(jù)beanName獲取bean以及存在 并且判斷是否可以覆蓋扁瓢,如果不運(yùn)行覆蓋 則拋出異常
                if (!this.allowBeanDefinitionOverriding) {
                    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound.");
                }

                if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                    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 (this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            } else {
                this.beanDefinitionNames.add(beanName);//記錄beanName
                this.frozenBeanDefinitionNames = null;
            }
             //注冊BeanDefinition
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        //重置BeanName對應(yīng)的緩存
        this.resetBeanDefinition(beanName);
    }

1.根據(jù)beanName獲取BeanDefintion 如果已近注冊的情況下详恼,并且設(shè)置了不允許Bean覆蓋則,需要拋出異常
2.加入map緩存
3.清除之前留下的對應(yīng)的BeanName的緩存

2.通過別名注冊BeanDefinition

   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)) {
            this.aliasMap.remove(alias);
        } else {
            if (!this.allowAliasOverriding()) {//若alias不允許被覆蓋引几,則拋出異常
                String registeredName = (String)this.aliasMap.get(alias);
                if (registeredName != null && !registeredName.equals(name)) {
                    throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'.");
                }
            }

            this.checkForAliasCircle(name, alias);
            this.aliasMap.put(alias, name);
        }
    }

3.通過監(jiān)聽器解析以及注冊既注冊完成

this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末昧互,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子她紫,更是在濱河造成了極大的恐慌硅堆,老刑警劉巖屿储,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贿讹,死亡現(xiàn)場離奇詭異,居然都是意外死亡够掠,警方通過查閱死者的電腦和手機(jī)民褂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來疯潭,“玉大人赊堪,你說我怎么就攤上這事∈ǎ” “怎么了哭廉?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長相叁。 經(jīng)常有香客問我遵绰,道長辽幌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任椿访,我火速辦了婚禮乌企,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘成玫。我一直安慰自己加酵,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布哭当。 她就那樣靜靜地躺著猪腕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪钦勘。 梳的紋絲不亂的頭發(fā)上码撰,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機(jī)與錄音个盆,去河邊找鬼脖岛。 笑死,一個(gè)胖子當(dāng)著我的面吹牛颊亮,可吹牛的內(nèi)容都是我干的柴梆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼终惑,長吁一口氣:“原來是場噩夢啊……” “哼绍在!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起雹有,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤偿渡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后霸奕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體溜宽,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年质帅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了适揉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡煤惩,死狀恐怖嫉嘀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情魄揉,我是刑警寧澤剪侮,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站洛退,受9級特大地震影響瓣俯,放射性物質(zhì)發(fā)生泄漏红淡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一降铸、第九天 我趴在偏房一處隱蔽的房頂上張望在旱。 院中可真熱鬧,春花似錦推掸、人聲如沸桶蝎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽登渣。三九已至,卻和暖如春毡泻,著一層夾襖步出監(jiān)牢的瞬間胜茧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工仇味, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留呻顽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓丹墨,卻偏偏與公主長得像廊遍,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子贩挣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容