默认标签的解析

Posted lkeji388

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了默认标签的解析相关的知识,希望对你有一定的参考价值。

默认标签的解析是在parseDefaultElement方法中进行的,方法中的功能一目了然 ,分别对4种不同的标签(import、alias、bean、beans)做了不同的处理:

  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标签的解析及注册

  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、首先用BeanDefinitionParserDelegate的parseBeanDefinitionElement方法进行元素解析,返回BeanDefinitionHolder类的实例bdHolder,经过这个方法,bdHolder实例已经包含我们配置文件中配置的各种属性了,例如class,name,id alias之类的属性。

  2、当返回的bdHolder不为空的情况下若存在默认标签的子节点下在用自定义属性,还需要再次对自定义标签进行解析。

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

  4、最后发出响应时间,通知相关的监听器,这个bean已经加载完成了。

   public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
        return this.parseBeanDefinitionElement(ele, (BeanDefinition)null);
    }

    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
        String id = ele.getAttribute("id");//解析ID属性
        String nameAttr = ele.getAttribute("name");//解析name属性
        List<String> aliases = new ArrayList();
      //分割name属性
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); if (beanDefinition != null) { if (!StringUtils.hasText(beanName)) { try {
            //如果不存在beanNames那么根据Spring中提供的命名规则为当前bean生成对应的beanName
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; } }

对spring的解析犹如剥洋葱,一层一层的进行,尽管现在只能看到对属性ID以及name的解析,Srping在外层又做了一个当前层的功能架构,在当前层完成的主要工作:

1、提取元素中的Id及name属性

2、进一步解析其他所有属性并统一封装至GenericBeanDefinition类型的实例中

3、如果检测到bean没有指定beanName,那么使用默认规则为Bean生成的beanName

4、如果获取到的信息封装到BeanDefinitionHolder的实例中

查看步骤(2)中对标签其他属性的解析过程

  public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {
        this.parseState.push(new BeanEntry(beanName));
        String className = null;
    //解析class属性
if (ele.hasAttribute("class")) { className = ele.getAttribute("class").trim(); } try { String parent = null;
      //解析parent属性
if (ele.hasAttribute("parent")) { parent = ele.getAttribute("parent"); }       //创建用于承载属性的AbstractBeanDefinition类型的GenericBeanDefinition AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
      //硬编码解析默认bean的各种属性
this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
      //提取Decription bd.setDescription(DomUtils.getChildElementValueByTagName(ele,
"description"));
      //解析元数据
this.parseMetaElements(ele, bd);
      //解析lookup-method属性
this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
   
this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
      //解析构造函数参数
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; }

创建用于属性记载的BeanDefintion

  BeanDefinition是一个接口,在spring中存在三种实现 GenericBeanDefinition,ChildBeanDefinition ,RootBeanDefinition,三种实现均继承了AbstractBeanDefinition

其中BeanDefinition是配置文件<bean>元素标签在容器中的内部表示形式。<bean>元素标签拥有class、scope、lazy-init等配置属性BeanDefinition则提供了相应的beanClass,

scope,lazyInit属性,BeanDefinition和<bean>中的属性一一对应。其中RootBeanDefintion是最常用的实现类,它对应一般性的<bean>元素标签。

  在配置文件中可以定义父<bean>和子<bean>,父<bean>用RootBeanDefintion表示,而子<bean>用ChildBeanDefintion表示,而没有父<bean>的<bean>就用RootBeanDefinition表示。AbstractBeanDefinition对两者共同的类信息进行抽象。

  Spring通过BeanDefintion将配置文件中的<bean>配置信息转换为容器的内部表示,并将这些BeanDefintion注册到BeanDefintionRegistry中。Spring容器的BeanDefintionRegistry就像是Spring配置信息的内存数据库,主要是以map的形式保存,后续操作直接用BeanDefintionRegistry中读取配置信息。

 













以上是关于默认标签的解析的主要内容,如果未能解决你的问题,请参考以下文章

4Spring 源码学习 ~ 默认标签的解析之 Bean 标签注册

Spring源码分析bean标签的解析及注册

如何通过代码设置片段标签?

Spring源码深度解析学习系列默认标签解析

jquery基本操作

Spring源码解析-默认标签解析-2