spring中xml标签加载解析的一般过程

来源:互联网 发布:服务器域名怎么看 编辑:程序博客网 时间:2024/05/20 11:33

默认标签的解析过程:

DefaultBeanDefinitonDocumentReader class中processBeanDefinition

(1)     该方法先解析element元素获得BeanDefinitionHolder,

(2)     由BeanDefintionParserDelegate对于holder进行装饰加工

(3)     由BeanDefinitionReaderUtils.registerBeanDefinition对于holder进行注册

(4)     之后发送注册事件getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder))

其中主要的方法如下:

protected voidprocessBeanDefinition(Elementele,BeanDefinitionParserDelegatedelegate) {

      BeanDefinitionHolderbdHolder=delegate.parseBeanDefinitionElement(ele);//(1)

      if (bdHolder !=null) {

         bdHolder = delegate.decorateBeanDefinitionIfRequired(ele,bdHolder);//(2)

         try {

            // Register the final decorated instance.

            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry());//(3)

         }

         catch(BeanDefinitionStoreExceptionex) {

            getReaderContext().error("Failed to register bean definition with name'" +

                   bdHolder.getBeanName() +"'", ele, ex);

         }

         // Send registration event.

         getReaderContext().fireComponentRegistered(newBeanComponentDefinition(bdHolder));//(4)

      }

   }

下面细节介绍首先是

(1)  对于element元素的解析

BeanDefinitionHolder bdHolder=delegate.parseBeanDefinitionElement(ele);   

delegate:BeanDefinitionParserDelegate该类主要是完成对于element的解析工作,位于org.springframework.beans.factory.xml包下

public BeanDefinitionHolderparseBeanDefinitionElement(Elementele){

      returnparseBeanDefinitionElement(ele,null);

}

该方法提供解析element,如果解析出错会返回一个null。

它调用如下的方法进行解析,string id ID_ATTRIBUTE 指的是常亮字符“id”<bean id>这里面的,name也是类似。

public BeanDefinitionHolderparseBeanDefinitionElement(Elementele,BeanDefinitioncontainingBean) {

//对应id name 等标签

      Stringid = ele.getAttribute(ID_ATTRIBUTE);

      StringnameAttr= ele.getAttribute(NAME_ATTRIBUTE);

      List<String>aliases= newArrayList<String>();

      if (StringUtils.hasLength(nameAttr)) {

         String[]nameArr= StringUtils.tokenizeToStringArray(nameAttr,MULTI_VALUE_ATTRIBUTE_DELIMITERS);

         aliases.addAll(Arrays.asList(nameArr));

      }

      StringbeanName= 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");

         }

      }

      if (containingBean ==null) {

         checkNameUniqueness(beanName,aliases, ele);

      }

      //解析的BeanDefinition放到GenericBeanDefintion中

      AbstractBeanDefinitionbeanDefinition= 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);

                   StringbeanClassName=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 (Exceptionex) {

                error(ex.getMessage(),ele);

                returnnull;

            }

         }

         String[]aliasesArray= StringUtils.toStringArray(aliases);

         return new BeanDefinitionHolder(beanDefinition,beanName, aliasesArray);

      }

      return null;

   }

 

(a)其中调用spring框架中的StringUtils类,并使用Java.util.StringTokenizer类进行字符串分割获得有用数据,然后添加到alisases:list中;

(b)先删除掉该beanName(id),然后再检测在当前的beandefinition nest中没有使用该bean,然后解析。

(c)  AbstractBeanDefinition beanDefinition =parseBeanDefinitionElement(ele,beanName,containingBean);

获得一个beandefinition,只不过这里将该对象引用给了它的抽象的父类,

该方法首先是

This.parseState.push(newBeanEntry(beanName));

 new  BeanEntry(String beanName)是beanEntry的一个构造方法,该类主要表示一个BeanDefinition 。


BeanDefinition是一个接口,其中定义了一些在xml中,bean<bean>定义的标签的对应的属性,其中有我们熟悉的lazyInit,

 

public interfaceBeanDefinition extends AttributeAccessor, BeanMetadataElement {

   StringSCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

   StringSCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

int ROLE_APPLICATION = 0;

   int ROLE_SUPPORT= 1;

   int ROLE_INFRASTRUCTURE= 2;

   StringgetParentName();

   void setParentName(StringparentName);

   StringgetBeanClassName();

   void setBeanClassName(StringbeanClassName);

   StringgetFactoryBeanName();

   voidsetFactoryBeanName(StringfactoryBeanName);

   StringgetFactoryMethodName();

   voidsetFactoryMethodName(StringfactoryMethodName);

   StringgetScope();

   void setScope(Stringscope);

   boolean isLazyInit();

   void setLazyInit(booleanlazyInit);

   String[]getDependsOn();

   void setDependsOn(String[]dependsOn);

   boolean isAutowireCandidate();

   void setAutowireCandidate(booleanautowireCandidate);

   boolean isPrimary();

   void setPrimary(booleanprimary);

   ConstructorArgumentValuesgetConstructorArgumentValues();

   MutablePropertyValuesgetPropertyValues();

   boolean isSingleton();

   boolean isPrototype();

   boolean isAbstract();

   int getRole();

   StringgetDescription();

   StringgetResourceDescription();

   BeanDefinitiongetOriginatingBeanDefinition();

 

}

AbstractBeanDefintion则是对于BeanDefinition接口的实现类,实现了其中操作属性的方法,可以将<bean> 中属性加载到该类中,是xml文件的一种对象转换。

 

之后className = ele.getAttribute(CLASS_ATTRIBUTE).trim();获得其classname.

并获得其父类string parent,然后用

AbstractBeanDefinition db =creatBeanDefinition(className,parent);

创建出beandefinition,该create方法则是利用了BeanDefinitionReaderUitls工具类的createBeanDefinition(parentName,className,this.readerContext.getBeanClassLoader())实现的,具体如下:

public staticAbstractBeanDefinitioncreateBeanDefinition(

         StringparentName,StringclassName,ClassLoader classLoader)throwsClassNotFoundException {

      GenericBeanDefinition bd =new GenericBeanDefinition();

      bd.setParentName(parentName);

      if (className !=null) {

         if (classLoader !=null) {

            bd.setBeanClass(ClassUtils.forName(className,classLoader));

         }

         else {

            bd.setBeanClassName(className);

         }

      }

      returnbd;

   }

之后是:

public AbstractBeanDefinitionparseBeanDefinitionElement(

         Elementele,String beanName,BeanDefinition containingBean) {

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

      StringclassName= null;

      if (ele.hasAttribute(CLASS_ATTRIBUTE)){

         className = ele.getAttribute(CLASS_ATTRIBUTE).trim();

      }

      try {

         Stringparent= null;

         if (ele.hasAttribute(PARENT_ATTRIBUTE)){

            parent = ele.getAttribute(PARENT_ATTRIBUTE);

         }

         AbstractBeanDefinitionbd =createBeanDefinition(className,parent);

 

         parseBeanDefinitionAttributes(ele,beanName, containingBean,bd);

         bd.setDescription(DomUtils.getChildElementValueByTagName(ele,DESCRIPTION_ELEMENT));

 

         parseMetaElements(ele,bd);

         parseLookupOverrideSubElements(ele,bd.getMethodOverrides());

         parseReplacedMethodSubElements(ele,bd.getMethodOverrides());

 

         parseConstructorArgElements(ele,bd);

         parsePropertyElements(ele,bd);

         parseQualifierElements(ele,bd);

 

         bd.setResource(this.readerContext.getResource());

         bd.setSource(extractSource(ele));

 

         returnbd;

      }……

接着是如上的解析beandefinition的属性,设置description,解析metaelements,并且解析subElements,解析替代方法子元素parseReplacedMethodSubElements,解析构造器中参数elements,解析属性elements,设置资源等等。

然后返回到parseBeanDefinitionElement():,这些解析的具体的内容可以参考郝佳编著的《spring源码深度解析》中第三章的内容。BeanDefintionParseDelegate中继续执行,

最后将这个beandefinition和beanname都放到beandefinitionholder中,返回。即返回到DefaultBeanDefinitionDocumentReader类下的processBeanDefintion()方法。

(2)  对于holder进行修饰(装饰)

bdHolder= delegate.decorateBeanDefinitionIfRequired(ele,bdHolder);

里面利用了NamespaceHandler,命名空间的修饰,是不是默认的标签还是用户自定义的,可以通过其内容之进行判断。默认的标志为"http://www.springframework.org/schema/beans"

,其他用户自定义的标签由相应的NamespaceHandler进行处理。

 

(3)  注册最终的装饰后的bdholder类,

// Register the final decorated instance.

   BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry());

使用相应的beandefinitionfactory进行相应的holder注册

public staticvoidregisterBeanDefinition(

         BeanDefinitionHolderdefinitionHolder,BeanDefinitionRegistryregistry)

         throwsBeanDefinitionStoreException {

 

      // Register bean definition under primary name.

      StringbeanName= definitionHolder.getBeanName();

      registry.registerBeanDefinition(beanName,definitionHolder.getBeanDefinition());

 

      // Register aliases for bean name, if any.

      String[]aliases= definitionHolder.getAliases();

      if (aliases !=null) {

         for (Stringaliase : aliases) {

            registry.registerAlias(beanName,aliase);

         }

      }

   }

DefaultListBeanFactory中有一个实现了registryBeanDefinition()的方法,可以参考。一种是通过beanName注册,另外一种是通过alias别名进行注册。

beanName注册是将BeanName和BeanDefinition一起以Map <key value>形式加入到BeanDefintionMap中,其步骤为

(a1)进行一些验证(方法属性是否有);

(a2)然后判断是否可以覆盖,不可则抛出异常;

(a3)然后添加beanName到map中;

(a4)最后则是重置所有对应的缓存。

存在于DefaultListableBeanFactory中:

   public void registerBeanDefinition(StringbeanName, BeanDefinition beanDefinition)

         throwsBeanDefinitionStoreException {

      Assert.hasText(beanName,"Bean name must not be empty");

      Assert.notNull(beanDefinition,"BeanDefinition must not be null");

      if (beanDefinitioninstanceofAbstractBeanDefinition) {

         try {

            ((AbstractBeanDefinition)beanDefinition).validate();

         }

         catch(BeanDefinitionValidationExceptionex) {

            throw newBeanDefinitionStoreException(beanDefinition.getResourceDescription(),beanName,

                   "Validation of bean definition failed",ex);

         }

      }

 

      BeanDefinitionoldBeanDefinition;

 

      synchronized (this.beanDefinitionMap){

         oldBeanDefinition= this.beanDefinitionMap.get(beanName);

         if (oldBeanDefinition!=null){

            if (!this.allowBeanDefinitionOverriding) {

                throw newBeanDefinitionStoreException(beanDefinition.getResourceDescription(),beanName,

                      "Cannot register bean definition [" +beanDefinition+ "] for bean '" +beanName+

                      "': There is already ["+oldBeanDefinition+ "] bound.");

            }

            else {

                if (this.logger.isInfoEnabled()) {

                   this.logger.info("Overriding bean definition for bean '" +beanName+

                         "': replacing ["+oldBeanDefinition+ "] with [" + beanDefinition+ "]");

                }

            }

         }

         else {

            this.beanDefinitionNames.add(beanName);

            this.frozenBeanDefinitionNames=null;

         }

         this.beanDefinitionMap.put(beanName,beanDefinition);

      }

 

      if (oldBeanDefinition!=null|| containsSingleton(beanName)) {

         resetBeanDefinition(beanName);

      }

   }

 

 

通过alias别名注册的情况则是SimpleAliasRegistry中的实现了该方法:

public voidregisterAlias(String name, Stringalias){

      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 {

         if(!allowAliasOverriding()) {

            StringregisteredName=this.aliasMap.get(alias);

            if (registeredName !=null && !registeredName.equals(name)) {

                throw new IllegalStateException("Cannot register alias '" +alias+ "' for name '" +

                      name + "': It is already registered for name '" + registeredName+"'.");

            }

         }

         checkForAliasCircle(name,alias);

         this.aliasMap.put(alias,name);

      }

   }

(b1)如果有alias别名和beanName相同的先从aliasmap中移除,

(b2)如果不允许相同别名的覆盖,则会抛出异常

(b3)检查是否有循环的情况A->B ,A->C->B的情况

(b4)将alias和name添加到别名map中

(4)注册事件传递(注册监听)// Send registration event.

         getReaderContext().fireComponentRegistered(newBeanComponentDefinition(bdHolder));

      readercontext中注册该监听事件

public voidfireComponentRegistered(ComponentDefinitioncomponentDefinition){

      this.eventListener.componentRegistered(componentDefinition);

   }

其中的参数可以是如下构造,显示本身,然后是内部的beandefinition和参考设置。

public BeanComponentDefinition(BeanDefinitionHolderholder){

      super(holder);

      findInnerBeanDefinitionsAndBeanReferences(holder.getBeanDefinition());

   }

 

0 0
原创粉丝点击