资讯专栏INFORMATION COLUMN

Spring源码阅读——ClassPathXmlApplicationContext(三)

gecko23 / 1353人阅读

摘要:在上一篇源码阅读二文章的最后,需要解析元素,创建实例完成必须的装配和进行最终的注册来完成元素的解析和注册,下面分别阅读三步的源码。

在上一篇Spring源码阅读——ClassPathXmlApplicationContext(二)文章的最后,需要解析bean元素,创建BeanDefinitionHolder实例、完成必须的装配和进行最终的注册bean来完成bean元素的解析和注册,下面分别阅读三步的源码。

创建BeanDefinitionHolder实例

BeanDefinitionHolder的创建是委托给BeanDefinitionParserDelegate这个代理类的parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean)方法来完成的,此方法的实现如下:

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
        // 获取id属性值
        String id = ele.getAttribute(ID_ATTRIBUTE);
        // 获取name属性值
        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
        //解析name属性值,将所有name放入List中
        List aliases = new ArrayList<>();
        if (StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
            aliases.addAll(Arrays.asList(nameArr));
        }
        // 赋值beanName为id
        String beanName = id;
        if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
            // 如果id为空,且name属性不为空,取第一个name为beanName
            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) {
            // 检查唯一性
            checkNameUniqueness(beanName, aliases, ele);
        }
        // 解析bean元素
        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
        if (beanDefinition != null) {
            // 如果beanName为空
            if (!StringUtils.hasText(beanName)) {
                try {
                    if (containingBean != null) {
                        // 生成默认的beanName
                        beanName = BeanDefinitionReaderUtils.generateBeanName(
                                beanDefinition, this.readerContext.getRegistry(), true);
                    }
                    else {
                        // 生成默认的beanName
                        beanName = this.readerContext.generateBeanName(beanDefinition);
                        // 通过beanClass生成一个alias
                        String beanClassName = beanDefinition.getBeanClassName();
                        if (beanClassName != null &&
                                beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                                !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                            aliases.add(beanClassName);
                        }
                    }
                }
                catch (Exception ex) {
                    error(ex.getMessage(), ele);
                    return null;
                }
            }
            // 得到别名数组
            String[] aliasesArray = StringUtils.toStringArray(aliases);
            // 创建BeanDefinitionHolder对象并返回
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        }

        return null;
    }

在上述源码中,调用了parseBeanDefinitionElement(ele, beanName, containingBean)方法创建AbstractBeanDefinition 实例,下面是此方法的实现:

public AbstractBeanDefinition parseBeanDefinitionElement(
            Element ele, String beanName, @Nullable BeanDefinition containingBean) {
        // 根据beanName创建BeanEntry实体,并且push BeanEntry
        this.parseState.push(new BeanEntry(beanName));
        // 获取class属性值
        String className = null;
        if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
            className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
        }
        // 获取parent属性值
        String parent = null;
        if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
            parent = ele.getAttribute(PARENT_ATTRIBUTE);
        }

        try {
            // 创建AbstractBeanDefinition实例
            AbstractBeanDefinition bd = createBeanDefinition(className, parent);
            // 设置AbstractBeanDefinition实例的其他各种属性
            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            // 获取子元素description
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
            // 获取子元素meta
            parseMetaElements(ele, bd);
            // 解析子元素lookup-method
            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 {
            // pop BeanEntry
            this.parseState.pop();
        }

        return null;
    }
如果有非默认命名空间,继续装饰此实例

decorateBeanDefinitionIfRequired(ele, bdHolder)接口的最终实现如下:

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

        BeanDefinitionHolder finalDefinition = definitionHolder;

        // 根据自定义属性装饰
       // 获取所有属性
        NamedNodeMap attributes = ele.getAttributes();
        for (int i = 0; i < attributes.getLength(); i++) {
            Node node = attributes.item(i);
            finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
        }

        // 装饰基于自定义嵌套元素的装饰
        // 获取所有嵌套元素
        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;
    }

此方法在存在非默认命名空间时,解析自定义的属性和嵌套元素,decorateIfRequired(node, finalDefinition, containingBd)方法的实现如下:

public BeanDefinitionHolder decorateIfRequired(
            Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {

        // 获取命名空间uri
        String namespaceUri = getNamespaceURI(node);
        // 如果不是默认命名空间uri
        if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
            // 获取命名空间handler
            NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
            if (handler != null) {
                // 调用此handler 的decorate方法创建BeanDefinitionHolder实例
                BeanDefinitionHolder decorated =
                        handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
                if (decorated != null) {
                    return decorated;
                }
            }
            else if (namespaceUri.startsWith("http://www.springframework.org/")) {
                error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
            }
            else {
                // A custom namespace, not to be handled by Spring - maybe "xml:...".
                if (logger.isDebugEnabled()) {
                    logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
                }
            }
        }
        return originalDef;
    }
注册最终的实例

接下来是往注册表中注册bean,BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry())的实现如下:

public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {

        String beanName = definitionHolder.getBeanName();
        // beanName 作为key,注册bean definition
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

        // beanName 作为key,注册alias
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    }

在SimpleBeanDefinitionRegistry类中,定义了注册bean definition的Mam对象,map初始大小为64,如下:
private final Map beanDefinitionMap = new ConcurrentHashMap<>(64);
registerBeanDefinition(beanName, definitionHolder.getBeanDefinition())

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

        Assert.hasText(beanName, ""beanName" must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }

通过这篇文章,学习了ClassPathXmlApplicationContext的启动解析默认命名空间中元素的解析过程,下面继续学习自定义命名空间中bean的解析。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/76389.html

相关文章

  • Spring源码阅读——ClassPathXmlApplicationContext

    摘要:在上一篇源码阅读二文章的最后,需要解析元素,创建实例完成必须的装配和进行最终的注册来完成元素的解析和注册,下面分别阅读三步的源码。 在上一篇Spring源码阅读——ClassPathXmlApplicationContext(二)文章的最后,需要解析bean元素,创建BeanDefinitionHolder实例、完成必须的装配和进行最终的注册bean来完成bean元素的解析和注册,下面...

    xbynet 评论0 收藏0
  • Spring源码阅读——ClassPathXmlApplicationContext

    摘要:在上一篇源码阅读二文章的最后,需要解析元素,创建实例完成必须的装配和进行最终的注册来完成元素的解析和注册,下面分别阅读三步的源码。 在上一篇Spring源码阅读——ClassPathXmlApplicationContext(二)文章的最后,需要解析bean元素,创建BeanDefinitionHolder实例、完成必须的装配和进行最终的注册bean来完成bean元素的解析和注册,下面...

    AndroidTraveler 评论0 收藏0
  • Spring源码阅读——ClassPathXmlApplicationContext(一)

    摘要:的继承关系继承了,实现了接口。是所有容器的顶级接口,中所有容器都是基于的。方法创建一个新的容器。在本方法中,最重要的是,调用这个方法解析配置文件,注册。 ClassPathXmlApplicationContext的继承关系 ClassPathXmlApplicationContext继承了AbstractXmlApplicationContext,实现了ApplicationCont...

    taowen 评论0 收藏0
  • Spring源码阅读——ClassPathXmlApplicationContext(四)

    摘要:在的方法中,遍历每一个节点,判断是否为默认命名空间中的节点,如果是非默认命名空间的,调用方法进行处理。在学习自定义标签解析之前,先写一个自定义标签的。 在DefaultBeanDefinitionDocumentReader的parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)方法中,遍历每一...

    silenceboy 评论0 收藏0
  • Spring源码阅读——ClassPathXmlApplicationContext(四)

    摘要:在的方法中,遍历每一个节点,判断是否为默认命名空间中的节点,如果是非默认命名空间的,调用方法进行处理。在学习自定义标签解析之前,先写一个自定义标签的。 在DefaultBeanDefinitionDocumentReader的parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)方法中,遍历每一...

    wmui 评论0 收藏0

发表评论

0条评论

gecko23

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<