Spring源码学习(二):默认标签的解析与Bean的注册

本文深入探讨Spring源码中bean标签的解析过程,包括BeanDefinition的组装、BeanName的生成、BeanDefinition的装饰以及注册。解析过程中涉及的方法如parseBeanDefinitionElement、decorateBeanDefinitionIfRequired和registerBeanDefinition等。此外,还介绍了alias、import和beans等默认标签的解析细节,展示了Spring如何处理bean的元信息和配置复用。
摘要由CSDN通过智能技术生成

目录

1 parseBeanDefinitionElement方法

1.1 BeanDefinition的组装

1.2 产生BeanName

2 decorateBeanDefinitionIfRequired方法

3 注册BeanDefinition

4 其它默认标签的解析

4.1 alias标签

4.2 import标签

4.3 beans标签


在parseDefaultElement中,可以看到,默认标签共有四种,其中做关键的当然是bean标签。所以下面就以Bean为例说明默认标签的解析。

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

首先看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));
        }

    }

程序逻辑为:

  • 首先调用BeanDefinitionParserDelegate类的parseBeanDefinitionElement方法,对传入的DOM元素进行解析。将解析到的各种属性封装进BeanDefinitionHolder对象
  • 如果上一步返回的BeanDefinitionHolder对象不为空,则进一步处理。假如默认标签的节点内包含了自定义标签,还需要调用decorateBeanDefinitionIfRequired方法进一步解析
  • 然后进行BeanDefinition的注册
  • 最后触发加载完成事件,以便相关监听器进行后续处理

1 parseBeanDefinitionElement方法

该方法源码如下:

    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
        String id = ele.getAttribute("id");
        String nameAttr = ele.getAttribute("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 (containingBean == null) {
            this.checkNameUniqueness(beanName, aliases, ele);
        }
        AbstractBeanDefinition beanDefinition = this.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);
                        }
                    }
                } catch (Exception var9) {
                    this.error(var9.getMessage(), ele);
                    return null;
                }
            }
            String[] aliasesArray = StringUtils.toStringArray(aliases);
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        } else {
            return null;
        }
    }

该方法首先解析出id和name属性,并将id作为Bean的唯一不可重复名称,name作为Bean的别名,从代码可以看出,name可以配置多个值,用逗号分隔。假如没有设置id,则取第一个name作为BeanName。然后在parseBeanDefinitionElement的重载方法中,进一步解析class、parent等属性,并进行BeanDefinition的组装,如果id和name都没有指定,则调用generateBeanName生成一个。最后,将生成的BeanDefinition和BeanName、AliasArray封装进BeanDefinitionHolder。

parseBeanDefinitionElement的重载版本解析过程如下(catch块省略),各个流程都加了注释:

    public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, @Nullable BeanDefinition containingBean) {
        this.parseState.push(new BeanEntry(beanName));
        //解析class属性
        String className = null;
        if (ele.hasAttribute("class")) {
            className = ele.getAttribute("class").trim();
        }
        //解析parent属性
        String parent = null;
        if (ele.hasAttribute("parent")) {
            parent = ele.getAttribute("parent");
        }
        try {
            //BeanDefinition组装过程
            AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
            //解析其他属性
            this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
            bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
            //解析元数据
            this.parseMetaElements(ele, bd);
            //解析look-up属性
            this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
            //解
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值