Spring--解析默认标签

测试:

BeanFactory beanFactory=new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
        TextService textService=(TextService)beanFactory.getBean("textService");
        textService.sayHello();

配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:p="http://www.springframework.org/schema/p" 
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
                        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
                        http://www.springframework.org/schema/context 
                        http://www.springframework.org/schema/context/spring-context-2.5.xsd  
                        http://www.springframework.org/schema/aop  
                        http://www.springframework.org/schema/aop/spring-aop-2.5.xsd  
                        http://www.springframework.org/schema/tx  
                        http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

    <!-- 新添加表时要添加 的位置 -->
    <bean id="textService" class="com.test.service.TextService">
        <meta key="msg" value="hello world"/>
    </bean>
</beans>

1 在DefaultBeanDefinitionDocumentReader的方法parseBeanDefinitions中对于标签的解析分为默认标签的解析和自定义标签的解析。而默认标签与自定义标签的的区分是根据命名空间来进行判断的。具体代码如下

BeanDefinitionParserDelegate类
public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";
public boolean isDefaultNamespace(String namespaceUri) {
        return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri));
    }
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    if (delegate.isDefaultNamespace(ele)) {
                        //默认标签的解析
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        //自定义标签的解析
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            //自定义标签的计息
            delegate.parseCustomElement(root);
        }
    }

默认标签的解析分为import、alias、bean、beans;对于beans标签及配置文件的最高父标签,采用深度优先遍历的方式,再次进入parseBeanDefinitions方法中进入解析。

2 bean标签的解析:BeanDefinitionParserDelegate-》parseBeanDefinitionElement

    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
        String id = ele.getAttribute(ID_ATTRIBUTE);
        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

        List<String> aliases = new ArrayList<String>();
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
        }
        //如果没有给id赋值,则将第一个name的值赋给id。
        String beanName = id;
        if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
            beanName = aliases.remove(0);
            if (logger.isDebugEnabled()) {
                logger.debug("No XML 'id' specified - using '" + beanName +
                        "' as bean name and " + aliases + " as aliases");
            }
        }
        //对name和alias的值与已经解析完成后存于HashSet中的name的值进行比较,即唯一性比较,成功则添加到HashSet中。
        if (containingBean == null) {
            checkNameUniqueness(beanName, aliases, ele);
        }

        //
        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
        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 (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);
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        }

        return null;
    }

当没有id和name是有一个创建beanName的逻辑,特整理如下。
这里写图片描述

public static String generateBeanName(
            BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean)
            throws BeanDefinitionStoreException {

        String generatedBeanName = definition.getBeanClassName();
        if (generatedBeanName == null) {
            if (definition.getParentName() != null) {
                generatedBeanName = definition.getParentName() + "$child";
            }
            else if (definition.getFactoryBeanName() != null) {
                generatedBeanName = definition.getFactoryBeanName() + "$created";
            }
        }
        if (!StringUtils.hasText(generatedBeanName)) {
            throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither " +
                    "'class' nor 'parent' nor 'factory-bean' - can't generate bean name");
        }

        String id = generatedBeanName;
        if (isInnerBean) {
            // Inner bean: generate identity hashcode suffix.
            id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
        }
        else {
            // Top-level bean: use plain class name.
            // Increase counter until the id is unique.
            int counter = -1;
            while (counter == -1 || registry.containsBeanDefinition(id)) {
                counter++;
                id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
            }
        }
        return id;
    }

比如:beanName生成:com.test.service.UserService#0
对、、等子标签的解析,返回GenericBeanDefinition对象,对象中以属性的形式存储各个标签的信息。
BeanDefinitionParserDelegate-》parseBeanDefinitionElement

public AbstractBeanDefinition parseBeanDefinitionElement(
            Element ele, String beanName, BeanDefinition containingBean) {

        this.parseState.push(new BeanEntry(beanName));

        String className = null;
        if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
            className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
        }

        try {
            String parent = null;
            if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
                parent = ele.getAttribute(PARENT_ATTRIBUTE);
            }
            //创建一个GenericBeanDefinition对象,          
            AbstractBeanDefinition bd = createBeanDefinition(className, parent);
            //设置各个属性的值。如class,是否懒加载lazyInit
            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
            //加载各个meta源数据
            //如:
            <bean id="textService" class="com.test.service.TextService">
                <meta key="" value=""/>
            </bean>
            parseMetaElements(ele, bd);
            //解析lookup-method标签,      http://blog.csdn.net/btwangzhi/article/details/78165862
            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            //解析replaced-method标签
            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
            //解析<constructor-arg>标签
            parseConstructorArgElements(ele, bd);
            //解析property标签
            parsePropertyElements(ele, bd);
            //解析qualifier标签
            parseQualifierElements(ele, bd);

            bd.setResource(this.readerContext.getResource());
            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;
    }

如上对一个标签进行了解析然后,生成BeanDefinitionHolder对象,构造器为id和包含了标签各种各样的属性值,还有别名。

2 alias标签的解析
alias标签解析基本就是获取name属性和alias属性的值进行环路检测,
应用场景为:

核心代码如下:

public boolean hasAlias(String name, String alias) {
        for (Map.Entry<String, String> entry : this.aliasMap.entrySet()) {
            String registeredName = entry.getValue();
            if (registeredName.equals(name)) {
                String registeredAlias = entry.getKey();
                return (registeredAlias.equals(alias) || hasAlias(registeredAlias, alias));
            }
        }
        return false;
    }

说明:比如A->B存在时,不允许出现A->C->B.

未完待续。。。
参考Spring源码深度解析。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值