上一篇随笔说到Spring对于默认标签和自定义标签的解析方法是不同的,这里详细看一下Spring对于默认标签的解析。

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        if(delegate.nodeNameEquals(ele, "import")) {
            this.importBeanDefinitionResource(ele);
        } else if(delegate.nodeNameEquals(ele, "alias")) {
            this.processAliasRegistration(ele);
        } else if(delegate.nodeNameEquals(ele, "bean")) {
            this.processBeanDefinition(ele, delegate);
        } else if(delegate.nodeNameEquals(ele, "beans")) {
            this.doRegisterBeanDefinitions(ele);
        }

    }

在这里对根节点的子节点的四种不同类型分别做了不同的处理。这四种解析中,对bean的解析最为复杂。所以我们进入函数processBeanDefinition。

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if(bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

            try {
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
            } catch (BeanDefinitionStoreException var5) {
                this.getReaderContext().error("Failed to register bean definition with name \'" + bdHolder.getBeanName() + "\'", ele, var5);
            }

            this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }

    }

 

这段代码中:

1、首先委托了BeanDefinitionParseDelegate对节点做了解析,并返回了一个BeanDefinitionHolder的实例,在这个实例中已经包含了配置文件中配置的各种属性了

2、如果在当前子节点中存在自定义属性,则还需要对自定义标签进行解析

3、解析完成后,需要对解析后的bdHolder进行注册,同样注册操作委托给了BeanDefinitionReaderUtils

4、最后发出响应事件,通知相关的监听器

 

我们先看解析节点的部分

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
        String id = ele.getAttribute("id");
        String nameAttr = ele.getAttribute("name");
        ArrayList aliases = new ArrayList();
        if(StringUtils.hasLength(nameAttr)) {
            String[] beanName = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
            aliases.addAll(Arrays.asList(beanName));
        }

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

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

        AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName1, containingBean);
        if(beanDefinition != null) {
            if(!StringUtils.hasText(beanName1)) {
                try {
                    if(containingBean != null) {
                        beanName1 = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
                    } else {
                        beanName1 = this.readerContext.generateBeanName(beanDefinition);
                        String aliasesArray = beanDefinition.getBeanClassName();
                        if(aliasesArray != null && beanName1.startsWith(aliasesArray) && beanName1.length() > aliasesArray.length() && !this.readerContext.getRegistry().isBeanNameInUse(aliasesArray)) {
                            aliases.add(aliasesArray);
                        }
                    }

                    if(this.logger.isDebugEnabled()) {
                        this.logger.debug("Neither XML \'id\' nor \'name\' specified - using generated bean name [" + beanName1 + "]");
                    }
                } catch (Exception var9) {
                    this.error(var9.getMessage(), ele);
                    return null;
                }
            }

            String[] aliasesArray1 = StringUtils.toStringArray(aliases);
            return new BeanDefinitionHolder(beanDefinition, beanName1, aliasesArray1);
        } else {
            return null;
        }
    }

这段代码中首先提取了当前节点的id和name,beanName默认为id,如果id为空,则spring会去别名中的第一个作为beanName。

然后spring会检查当前beanName是否唯一,在BeanDefinitionParseDelegate中维护了一套已用过的beanName以及alias的集合,如果bean的beanName和alias和已存在的名字重复,则会抛错。

进一步解析节点的所有属性,并统一封装到GenericBeanDefinition中。

如果发现当前bean的beanName为空,则使用默认规则为其自动生成beanName。

最后将所有信息封装到BeanDefinitionHolder中返回。

进入到parseBeanDefinitionElement方法中

public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {
        this.parseState.push(new BeanEntry(beanName));
        String className = null;
        if(ele.hasAttribute("class")) {
            className = ele.getAttribute("class").trim();
        }

        try {
            String ex = null;
            if(ele.hasAttribute("parent")) {
                ex = ele.getAttribute("parent");
            }

            AbstractBeanDefinition bd = this.createBeanDefinition(className, ex);
            this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
            this.parseMetaElements(ele, bd);
            this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            this.parseConstructorArgElements(ele, bd);
            this.parsePropertyElements(ele, bd);
            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;
    }

在this.createBeanDefinition方法中,Spring会生产一个GenericBeanDefinition实例,在其属性里设置了当前节点的父类parent,以及className类名的信息。

在this.parseBeanDefinitionAttributes方法中对于一些属性进行了解析

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) {
        if(ele.hasAttribute("singleton")) {
            this.error("Old 1.x \'singleton\' attribute in use - upgrade to \'scope\' declaration", ele);
        } else if(ele.hasAttribute("scope")) {
            bd.setScope(ele.getAttribute("scope"));
        } else if(containingBean != null) {
            bd.setScope(containingBean.getScope());
        }

        if(ele.hasAttribute("abstract")) {
            bd.setAbstract("true".equals(ele.getAttribute("abstract")));
        }

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

        bd.setLazyInit("true".equals(lazyInit));
        String autowire = ele.getAttribute("autowire");
        bd.setAutowireMode(this.getAutowireMode(autowire));
        String dependencyCheck = ele.getAttribute("dependency-check");
        bd.setDependencyCheck(this.getDependencyCheck(dependencyCheck));
        String autowireCandidate;
        if(ele.hasAttribute("depends-on")) {
            autowireCandidate = ele.getAttribute("depends-on");
            bd.setDependsOn(StringUtils.tokenizeToStringArray(autowireCandidate, ",; "));
        }

        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));
            }
        }

        if(ele.hasAttribute("primary")) {
            bd.setPrimary("true".equals(ele.getAttribute("primary")));
        }

        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);
        }

        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);
        }

        if(ele.hasAttribute("factory-method")) {
            bd.setFactoryMethodName(ele.getAttribute("factory-method"));
        }

        if(ele.hasAttribute("factory-bean")) {
            bd.setFactoryBeanName(ele.getAttribute("factory-bean"));
        }

        return bd;
    }

在这里我们可以看到其中不少属性是我们经常使用的,当然也有一些属性不太熟悉。这里大致查了一下资料,简单介绍这些属性的意义:

scope:

对象在spring容器(IOC容器)中的生命周期。共有五中取值。singleton和protoType大家比较熟悉。另外三种request,session和global session只适用于web应用。

abstract:

当前bean是否为抽象类,默认为false

lazy-init:

延迟初始化,在ApplicationContext中默认配置时,spring会在应用启动时就对容器中的bean进行实例化,如果设置了延迟加载,则spring会在第一次使用该bean时初始化该bean。

autowire:

设置bean自动装配模式。可选5种模式   no:不使用自动装配。Bean的引用必须通过ref元素定义。byName:通过名字进行装配  byType:根据类型进行装配 constructor:和byType类似,不过是应用于通过构造函数注入的方式。autoDetect:通过对bean检查类的内部自动选择constructor还是byType。

dependency-check:

依赖检查的模式。

depends-on:

实例化时,依赖的bean,spring会在实例化当前bean之前先实例化依赖的bean。一般不需特别设置,spring会提供一套默认对依赖的检查和实例化的逻辑。

autowire-candidate:

当自动注入的类的实现类有多个时,有两种方案,一种是设置某一个实现类的autowire-candidate属性为false,则该类不参与自动注入。或者设置依赖注入的对象的autowire-candidate为指定实现类。

primary:

primary属性为true时,自动装配时当出现多个Bean的候选者时,属性primary=true的Bean被作为首选者。

init-method:

定义spring 容器在初始化bean之前的所做的操作。

destroy-method:

定义spring 容器在容器销毁之前的所做的操作。

factory-method 和 factory-bean:

spring IoC注入方式除了我们常见的set注入和构造器注入,还可以通过工厂方式注入。工厂分静态工厂和普通工厂。

如果想用某一个静态工厂来实例化bean,可以使用如下配置:

<bean name="production" class="com.wuzhe.factory.StaticFactory" factory-method="getProduction"/>

如果想通过普通工厂来实例化bean,可以使用如下配置:

<bean name="factory" class="com.wuzhe.factory.Factory"/>
    <bean name="production" factory-bean="factory" factory-method="getProduction"/>

 

接下来是解析子节点的meta属性:  this.parseMetaElements(ele, bd)

meta属性是在定义bean时额外添加的说明。例如:

<bean id="myBean" class="com.wuzhe.bean.MyBean">
        <meta key="author" value="wuzhe"></meta>
    </bean>

这里的meta属性并不会体现在myBean中,当需要meta信息的时候可以通过BeanDefinition.getAttribute(key)方法获取

 

接下来是解析节点的lookup-method:

this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());

先来看一下这个属性的用法,我们把lookup-method称之为获取器注入。这是一种特殊的方法注入,它是把一个方法声明为返回某个类型的bean,这样可用在设计有些可插拔的功能上,解除程序依赖。

举例说明,假设GetFood类中有一个Food getFood()方法。然后Bread和Cake分别继承Food类。当我们希望getFood()返回Bread类型的bean,我们可以这样配置:

<bean id="getFoodTest" class="com.wuzhe.lookup.GetFood">
        <lookup-method name="getFood" bean="bread"/>
    </bean>
    <bean id="bread" class="com.wuzhe.food.Bread"/>
    <bean id="cake" class="com.wuzhe.food.Cake"/>

如果我们想让getFood()方法返回cake时,只要修改bean属性就可以了

进入到解析lookup-method方法里面

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

        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
            if(this.isCandidateElement(node) && this.nodeNameEquals(node, "lookup-method")) {
                Element ele = (Element)node;
                String methodName = ele.getAttribute("name");
                String beanRef = ele.getAttribute("bean");
                LookupOverride override = new LookupOverride(methodName, beanRef);
                override.setSource(this.extractSource(ele));
                overrides.addOverride(override);
            }
        }

    }

上面这段代码会将lookup-method要mock返回的方法和bean封装在LookupOverride类中,并添加到bd的methodOverrides属性中。

 

接下来是解析replace-method属性

this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

replace-method更加强大,不但可以替换bean,还可以替换原有方法的逻辑。它可以将bean中的方法替换成另一个继承MethodReplace的类reimplement的实现

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

        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
            if(this.isCandidateElement(node) && this.nodeNameEquals(node, "replaced-method")) {
                Element replacedMethodEle = (Element)node;
                String name = replacedMethodEle.getAttribute("name");
                String callback = replacedMethodEle.getAttribute("replacer");
                ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
                List 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);
            }
        }

    }

这里解析replace-method的思路和lookup-method类似,都是讲元素的属性封装一下,并添加到bd的methodOverrides属性中。不同的是replace-method属性封装在RepalceOverride中。

 

接下来看对构造函数的解析

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

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

                        valueHolder1.setSource(this.extractSource(ele));
                        if(bd.getConstructorArgumentValues().hasIndexedArgumentValue(value)) {
                            this.error("Ambiguous constructor-arg entries for index " + value, ele);
                        } else {
                            bd.getConstructorArgumentValues().addIndexedArgumentValue(value, valueHolder1);
                        }
                    } finally {
                        this.parseState.pop();
                    }
                }
            } catch (NumberFormatException var19) {
                this.error("Attribute \'index\' of tag \'constructor-arg\' must be an integer", ele);
            }
        } else {
            try {
                this.parseState.push(new ConstructorArgumentEntry());
                Object value1 = this.parsePropertyValue(ele, bd, (String)null);
                ValueHolder valueHolder2 = new ValueHolder(value1);
                if(StringUtils.hasLength(typeAttr)) {
                    valueHolder2.setType(typeAttr);
                }

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

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

    }

spring对constructor-arg是否存在index属性的处理流程稍有不同,不同在于如果存在index属性,spring会将type、name和index属性封装在ValueHolder并添加至bd的constructorArgumentValues的indexedArgumentValues属性中,如果不存在则添加至genericArgumentValue属性中。

 

解析property属性和constructor-arg的过程类似

public void parsePropertyElement(Element ele, BeanDefinition bd) {
        String propertyName = ele.getAttribute("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)) {
                    this.error("Multiple \'property\' definitions for property \'" + propertyName + "\'", ele);
                    return;
                }

                Object val = this.parsePropertyValue(ele, bd, propertyName);
                PropertyValue pv = new PropertyValue(propertyName, val);
                this.parseMetaElements(ele, pv);
                pv.setSource(this.extractSource(ele));
                bd.getPropertyValues().addPropertyValue(pv);
            } finally {
                this.parseState.pop();
            }

        }
    }

 

解析qualifier

Spring在进行自动注入时,容器中候选的Bean有且只有一个,当有多个候选Bean的时候可以通过Qualifier指定注入Bean的名称。

具体解析过程和之前大同小异

public void parseQualifierElement(Element ele, AbstractBeanDefinition bd) {
        String typeName = ele.getAttribute("type");
        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);
                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();
            }
        }
    }

 

至此,对bean节点的属性解析就完成了,相当于spring将配置文件转换成了内存中的GenericBeanDefinition对象。xml中的属性都可以在GenericBeanDefinition找到储存的位置。

 

解析完bean后,就需要对beanDefinition进行注册,注册我理解就是把解析的beanDefinition存放在内存中,统一管理。在XmlFactory中,所有的beanDefinition缓存都存放在了它的父类DefaultListableBeanFactory的

beanDefinitionMap中,key值为beanName。

我们看一下注册的源码

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

        BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
        if(oldBeanDefinition != null) {
            if(!this.isAllowBeanDefinitionOverriding()) {
                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(!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 {
            if(this.hasBeanCreationStarted()) {
                Map var4 = this.beanDefinitionMap;
                synchronized(this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    ArrayList updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    if(this.manualSingletonNames.contains(beanName)) {
                        LinkedHashSet updatedSingletons = new LinkedHashSet(this.manualSingletonNames);
                        updatedSingletons.remove(beanName);
                        this.manualSingletonNames = updatedSingletons;
                    }
                }
            } else {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                this.manualSingletonNames.remove(beanName);
            }

            this.frozenBeanDefinitionNames = null;
        }

        if(oldBeanDefinition != null || this.containsSingleton(beanName)) {
            this.resetBeanDefinition(beanName);
        }

    }

在这段代码中

1、首先对传入的beanDefinition做了合法性的校验

2、然后根据beanName查找当前beanDefinitionMap缓存中是否已有相应的beanDefinion。如果有且当前设置了不允许bean覆盖,则会抛错,若允许覆盖,则用当前beanDefinition覆盖旧的beanDefinition,并清除缓存中旧的bean信息。

3、如果beanDefinitionMap缓存中不存在旧的beanDifinition, 则在beanDefinitionMap中存放当前beanDefinition。

这里涉及到的几个缓存:beanDefinitionMap很好理解,manualSingletonNames的含义并不清楚,这里留个疑问,后续若学习到相关知识,再来补充。

 

注册好了beanDefinition,接下来就是注册alias。注册的alias和beanName的对应关系存放在了aliasMap中

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 {
            String registeredName = (String)this.aliasMap.get(alias);
            if(registeredName != null) {
                if(registeredName.equals(name)) {
                    return;
                }

                if(!this.allowAliasOverriding()) {
                    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);
        }

    }

注册别名的过程还是很容易理解的:

1、若beanName和alias相同,则无需处理,并在缓存中删除alias

2、若存在alias注册了其他beanName,则根据是否允许覆盖的设置,进行相应处理

3、循环检查alias

4、注册alias

 至此对bean默认标签的解析和注册就完成了