spring源码之解析默认命名空间

    上篇博文讨论了spring解析配置文件applicationContext.xml的document对象的大致流程:大体分为默认命名空间和非默认命名空间的解析。默认命名空间为bean标签,alias标签和import标签,而非默认空间主要为aop标签 和管理事务的标签。

	
	if (delegate.isDefaultNamespace(root.getNamespaceURI())) {
			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;
					String namespaceUri = ele.getNamespaceURI();
					//默认命名空间
					if (delegate.isDefaultNamespace(namespaceUri)) {
						parseDefaultElement(ele, delegate);
					}
					else {
					//非默认命名空间
					delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
		
			delegate.parseCustomElement(root);
		}

     默认命名空间的解析

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
                //解析import标签
		if (DomUtils.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		 //解析alias标签
		else if (DomUtils.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		//解析bean标签
		else if (DomUtils.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
	}

     非默认命名空间的解析

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
		String namespaceUri = ele.getNamespaceURI();
		//给相应的命名空间选择解析器
            NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
                //调用相应解析器的解析方法
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

     从上面就可以对spring解析配置文件的过程一目了然了。以后着重探讨每个解析的细节。


一、解析bean标签

      从上面可以看出,解析bean标签,调用的processBeanDefinition()方法

//【代码清单】: BeanDefinitionParserDelegate解析bean
protectedvoid processBeanDefinition(Elementele, BeanDefinitionParserDelegate delegate) {
//1.委托给BeanDefinitionParserDelegate来完成对bean元素的处理,这个类包含了具体的bean解析过程,解析后把解析bean文件得到的信息放到BeanDefinition里,他是bean信息的主要载体,也是ioc容器的管理对象;然后把beanDefinition交给BeanDefinitonHold管理
       BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
       if (bdHolder != null) {
          //2.用于扩展BeanDefinition
           bdHolder= delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
           try {
               //3.向ioc容器注册,实际上是放到放到ioc容器DefaultListableBeanFactory的一个map里
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry());
           }
           // 4.向IOC容器发送时间,表示解析和注册完成
           getReaderContext().fireComponentRegistered(newBeanComponentDefinition(bdHolder));
       }
    }

  从上面可以看到,解析bean标签,其实就是把bean标签里面的配置信息,封装到beanDefinition对象,然后把这个对象放到容器application的一个map中。我们先来看看它是怎么放进map中,再来看它是如何封装的。


(1)把封装对象放进容器

     我们来看看BeanDefinitionReaderUtils的registerBeanDefinition()方法

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

		// Register bean definition under primary name.
          //获得beanDefinition对象的名字
	String beanName = definitionHolder.getBeanName();
	  //把对象放进容器
	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

		// Register aliases for bean name, if any.
		String[] aliases = definitionHolder.getAliases();
		if (aliases != null) {
			for (int i = 0; i < aliases.length; i++) {
				registry.registerAlias(beanName, aliases[i]);
			}
		}
	}

      这个方法传进2个参数,一个是容器(registy),一个是要放进容器的对象(beanDefinition),这个BeanDefinitionRegistry是一个接口,前面实例化的容器DefaultListableBeanFactory是它 的一个实现类。这里调用DefaultListableBeanFactory.registerBeanDefinition()方法,把对象放进容器。

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

		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
			        //校验
				((AbstractBeanDefinition) beanDefinition).validate();
			}
		}
	synchronized (this.beanDefinitionMap) {
			Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
			if (oldBeanDefinition != null) {

			}
			else {
				this.beanDefinitionNames.add(beanName);
				this.frozenBeanDefinitionNames = null;
			}
	//把beanDefinition以beanName为key,beanDefinition为value放进一个map中
			this.beanDefinitionMap.put(beanName, beanDefinition);

			resetBeanDefinition(beanName);
		}
	}

    所以,我们平时说把一个对象放进容器里面,其实就是把这个对象放进容器对象BeanFactory的一个map中,下面我们就来看看spring是如何把xml中的配置封装成对象的。


(2)把配置信息封装成对象

     bean标签里面有什么属性呢?我们先来看bean标签

    <bean id="" 
         name=""
         <!--使用Class属性指定类的默认构造方法创建一个单例Bean,名称由id属性指定-->
         class=""
        <!--作用域,默认为singleTon -->
         scope=""
         <!-- 初始化时调用的方法 -->
         init-method=""
         <!-- 对象在销毁时要调用的方法 -->
         destroy-method=""
<!-- 要求Spring采用何种方式来检查bean的setting属性设置情况 -->
         dependency-check="default"
<!-- 该bean初始化之前,要求Spring容器事先将所依赖的bean也实例化 -->
         depends-on=""
        <!-- 指定一个工厂方法来创建此bean -->
         factory-bean=""
<!-- 对象在销毁时要调用的方法 -->
         factory-method=""
<!-- 如果设置为true,那么Spring容器认定此bean为抽象的,并且不会对它进行初始化 -->
         abstract="true"
<!-- 如果设置为false,该bean不会被当作其它bean的autowire候选对象 -->
         autowire-candidate="default"
<!-- 如果该bean需要autowire的话,声明采用哪一种autowire。可选的值有:byType,byname,constractor,autodetect或no -->
         autowire="default"
<!-- 该bean被初始化或被注入到别的bean中时,Spring容器回调该方法 -->
         lazy-init="default"
<!-- 指定bean在配置文件中的父类 -->
         parent=""
<!-- 对象在销毁时要调用的方法 -->
         primary="true">
     </bean>

     和struct2解析标签一样,一个标签有自身带的属性,还会有子标签。

    <!-- property标签用于对bean实例中的属性进行赋值,对于基本数据类型的值可由value属性直接指定,而ref则表示对其他bean实例的引用-->   
   <property name="属性的名称" ref="用引用的bean的名称" value="属性值">       
   </property>
   <!-- private String name; -->
    <property name="属性的名称" value="属性值">
           
    </property>
    <!-- private BeanFactory factory; -->
    <property name="">
             <!创建一个内部匿名Bean实例赋值给指定的属性-->
           <bean class=""></bean>
    </property>
   <!-- private List<BeanFactory>factory; -->
    <property name="">
         <!-- list标签用于创建一个list类型的实例赋值给指定的List类型属性,List实例中的元素通过value或ref子标签指定。对于基本数据类型的元素由value标签生成,如果需要引用其他bean实例作为set元素的话,可由ref标签指定 -->
           <list>
              <value></value>
              <ref bean=""/>
           </list>
    </property>
    <!-- private Map<BeanFactory>factory; -->
    <property name="">
       <!-- Map标签用于创建一个Map类型的实例赋值给指定的Map类型属性,Map实例中的元素通过entry标签的key属性指定,值则可通过value或ref子标签指定。对于基本数据类型的元素由value标签生成,如果需要引用其他bean实例的话,可由ref标签指定 -->
           <map>
              <entry key=""key-ref="" value=""value-ref=""></entry>
           </map>
    </property>
 
  <!-- private Set<BeanFactory>factory; -->
    <property name="">
           <!-- set标签用于创建一个set类型的实例赋值给指定的set类型属性,set实例中的元素通过value或ref子标签指定。对于基本数据类型的元素由value标签生成,如果需要引用其他bean实例作为set元素的话,可由ref标签指定 -->
           <set>
              <value>
              </value>
              <ref bean=""local="" parent=""/>
           </set>
    </property>
    <property name="">
         <!-- 创建一个properties类型的实例赋给指定的properties类型属性 -->
           <props>                                                                                        <prop key="properties元素的key">properties元素的value</prop>
           </props>
    </property>
        <!--使用方法来代替getter注入。指定一个方法,它会在运行被复写从而返回一个指定的bean。这就是我们常说的getter注入 -->
    <lookup-method bean="" name=""/>
         <!-- 用一个新的实现来代替bean的某个方法 -->
    <replaced-method name="" replacer="">
    </replaced-method>
<!-- 想要让@Autowired方式按照name方式注入,可以结合@Qualifier("XX")使用,让@Autowired按照byName方式装配,消除歧义-->
       <qualifier value=""type="org.springframework.beans.factory.annotation.Qualifier">
       </qualifier>
       <meta key=""value=""/>
        <!-- 通过传入相应的构造参数进行bean实例化,constructor-arg标签用于指定一个构造参数,其index属性表明当前是第几个构成参数(从0开始),type属性声明构造参数的类型,构造参数的值如果是基本数据类型可由value属性直接指定,如果是对象的引用,则由ref属性指定 -->
       <constructor-arg index="从0开始的序号" type="构造参数的类型" value="构造参数的值" ref="要引用bean的名称">
        </constructor-arg>
       <!--用来描述Spring context或每个bean元素。虽然它会被Spirng容器所忽略,但<description>元素可以通过工具生成属于你的Spring context文档-->
        <description>
        </description>
    </bean>

    封装xml信息到对象,那么,那个对象必然有每个对应属性来存储。因beanDefinition代码较多,这里就不列出来了。下面我们来看看spring是如何封装这些属性的。

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele,BeanDefinition containingBean) {
      //得到bean的id和name <bean id=""name="" class="">
       String id = ele.getAttribute(ID_ATTRIBUTE);
       String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
       List aliases = new ArrayList();
      //如果配置了多个name值,把name分割放到一个list集合中
       if (StringUtils.hasLength(nameAttr)) {
           String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr,BEAN_NAME_DELIMITERS);
           aliases.addAll(Arrays.asList(nameArr));
       }
      //把id作为bean的名字标识
       String beanName = id;
       if (!StringUtils.hasText(beanName) &&!aliases.isEmpty()) {
      //如果id 为null name都不为null,则以第一个值为bean的名字
           beanName = (String) aliases.remove(0);
       }
     //以beanname检查是否有相同的bean
       if (containingBean == null) {
           checkNameUniqueness(beanName, aliases, ele);
       }
     //解析后把解析bean文件得到的信息放到BeanDefinition里,他是bean信息的主要载体,也是ioc容器的管理对象
       AbstractBeanDefinition beanDefinition =parseBeanDefinitionElement(ele, beanName, containingBean);
       if (beanDefinition != null) {
           if (!StringUtils.hasText(beanName)) {
              try {
                  if (containingBean != null) {
            //如果没有beanName,生成beanName
                     beanName = BeanDefinitionReaderUtils.generateBeanName(
                            beanDefinition, this.readerContext.getRegistry(),true);
                  }
                  else {
          //得到beanName和ClassName
                     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);
                     }
                  }
              }     
           }
           String[] aliasesArray = StringUtils.toStringArray(aliases);
           return new BeanDefinitionHolder(beanDefinition, beanName,aliasesArray);
       }
          return  null;
    }

      这里大体的流程就是,封装bean属性信息到beanDefinition,然后把beanDefintion进一步封装到BeanDefinitionHolder,这个BeanDefinitionHolder主要是管理BeanDefinition的,通过这个BeanDefinitionHolder就可以获取BeanDefinition信息

public class BeanDefinitionHolder implements BeanMetadataElement {

	private final BeanDefinition beanDefinition;

	private final String beanName;

	private final String[] aliases;
	
}

     那他是怎么封装bean信息到beanDefinition对象的呢?

//【代码清单】生成beanDefinition对象

public AbstractBeanDefinition parseBeanDefinitionElement(
           Element ele, String beanName, BeanDefinitioncontainingBean) {
       this.parseState.push(new BeanEntry(beanName));
       String className = null;
      //获得class属性<bean id="" name="" class=""/>
       if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
           className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
       }
        //获得parent属性
       try {
           String parent = null;
           if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
              parent = ele.getAttribute(PARENT_ATTRIBUTE);
           }
       //1.创建BeanDefinition
    AbstractBeanDefinition bd = createBeanDefinition(className,parent);
      //2.封装属性到BeanDefinition对象
    parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
      //设置Descript属性           
      bd.setDescription(DomUtils.getChildElementValueByTagName(ele,DESCRIPTION_ELEMENT));
            //3.对bean元素(二级类目)进行解析,如<bean><property/><bean>中的<property/>
             //<meta>
           parseMetaElements(ele, bd);
             //LookupOverrideSub
           parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
             //ReplacedMethodSub
           parseReplacedMethodSubElements(ele,bd.getMethodOverrides());
            //ConstructorArg
           parseConstructorArgElements(ele, bd);
            //解析bean的property属性
           parsePropertyElements(ele, bd);
            //qualifiy
           parseQualifierElements(ele, bd);
           bd.setResource(this.readerContext.getResource());
           bd.setSource(extractSource(ele));
           return bd;
       }
       finally {
           this.parseState.pop();
       }
 
       return null;
    }

     这里先实例化一个beanDefinition对象,然后封装bean的属性,最后封装bean的子标签。

①实例化BeanDefinition对象

【代码清单】创建createBeanDefinition
publicstatic AbstractBeanDefinition createBeanDefinition(
           String parentName, String className, ClassLoaderclassLoader) throws ClassNotFoundException {
           //new一个beanDefinition
       GenericBeanDefinition bd = new GenericBeanDefinition();
       bd.setParentName(parentName);
       if (className != null) {
           if (classLoader != null) {
              bd.setBeanClass(ClassUtils.forName(className,classLoader));
           }
           else {
              bd.setBeanClassName(className);
           }
       }
       return bd;
    }

②封装bean属性值到BeanDefinition对象中

//【代码清单】组合信息到BeanDefinition
    public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, StringbeanName,
           BeanDefinition containingBean, AbstractBeanDefinition bd){
       if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
           // 获得scope属性,并设置scope属性
           bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
           //spring 2.x作用域是用scope,有了scope就不用有singleton,否则报错
           if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
           error("Specifyeither 'scope' or 'singleton', not both", ele);
           }
       }
       elseif (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
// Spring 1.x"singleton" 属性,如果为真,则scope为singleton,否则为prototype
    bd.setScope(TRUE_VALUE.equals(ele.getAttribute(SINGLETON_ATTRIBUTE)) ?BeanDefinition.SCOPE_SINGLETON: BeanDefinition.SCOPE_PROTOTYPE);
       }
       elseif (containingBean != null) {    
 // 如果内钳了一个bean,以里面的bean的作用域的scope为准
           bd.setScope(containingBean.getScope());
       }
      //获得abstract属性,true or false
       if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {       bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
      //以下其他属性通过set方法添加到BeanDefinition中。代码省略。
       return bd;
    }

    封装属性很简单,无非就是用set()方法,把xml中相应属性的值,设置到beanDefinition对象上。

 ③封装bean子元素属性到对象中

 

     解析子标签的,重点讲解解析property。原理都是把property的各个属性封装到不通的对象中。如property中的bean封装到beanDefinitionHolder,ref属性封装到RuntimeBeanReference,vale属性封装到TypedStringValue,map封装到managedMap,list封装到managedList,set封装到managedSet.

//【代码清单】得到property标签
public void parsePropertyElements(ElementbeanEle, BeanDefinition bd) {
         //遍历元素下的所有子节点
       NodeList nl = beanEle.getChildNodes();
       for (int i = 0; i < nl.getLength(); i++) {
           Node node = nl.item(i);
           if (node instanceof Element && DomUtils.nodeNameEquals(node, PROPERTY_ELEMENT)) {
            //在判断是property属性后,对其解析
              parsePropertyElement((Element) node, bd);
           }
       }
    }
     这个property标签,记录的就是javaBean的属性值。
//【代码清单】获得property属性
public void parsePropertyElement(Element ele, BeanDefinition bd) {
        //得到name属性<property name="">
       String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
       if (!StringUtils.hasLength(propertyName)) {
             //name属性为空,返回
           return;
       }
       this.parseState.push(new PropertyEntry(propertyName));
       try {
             //name属性相同,返回
           if (bd.getPropertyValues().contains(propertyName)) {
              return;
           }
     //解析,解析结果会封装到PropertyValue对象中,然后设置到BeanDefinition中去
           Object val = parsePropertyValue(ele, bd, propertyName);
           PropertyValue pv = new PropertyValue(propertyName, val);
           parseMetaElements(ele, pv);
           pv.setSource(extractSource(ele));
           bd.getPropertyValues().addPropertyValue(pv);
       }
       finally {
           this.parseState.pop();
       }
    }

    property有什么属性呢?

<!-【代码清单】property属性>
   <!---------------给数组注入值----------------------->
    <property name=”属性” >
        <list>
             <value></value>
        </list>
    </property> 
    <!---------------给list集合注入值----------------------->
    <property name=”属性” >
        <list>
            <ref bean=’bean对象名’/>
        </list>
    </property>
(1)解析value和ref
//【代码清单】解析property
    public Object parsePropertyValue(Element ele, BeanDefinition bd, StringpropertyName) {
       String elementName = (propertyName != null) ?
"<property> element for property '" + propertyName + "'" :
                     "<constructor-arg>element";
     // 获得子元素 ref, value, list, etc.代码省略
       NodeList nl = ele.getChildNodes();
 //这里判断property的属性,是ref还是value,不允许同时是ref和value.部分代码省略
       boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
       boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
      
         //如果是ref,创建一个ref的数据对象RuntimeBeanReference,这个对象封装了ref的信息
       if (hasRefAttribute) {
           String refName = ele.getAttribute(REF_ATTRIBUTE);
           RuntimeBeanReference ref = new RuntimeBeanReference(refName);
           ref.setSource(extractSource(ele));
           return ref;
       }
       //如果是value,创建一个value的数据对象TypedStringValue ,这个对象封装了value的信息
       elseif (hasValueAttribute) {
           TypedStringValuevalueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
           valueHolder.setSource(extractSource(ele));
           return valueHolder;
       }
      //如果还有子元素,如map.list.set,触发对子元素的解析.
       elseif (subElement != null) {
           return parsePropertySubElement(subElement, bd);
       }
    }
(2)解析其他属性
//【代码清单】解析其他子元素
    public Object parsePropertySubElement(Element ele,BeanDefinition bd, String defaultTypeClassName) {
       if (!isDefaultNamespace(ele.getNamespaceURI())) {
           return parseNestedCustomElement(ele, bd);
       }
       //解析各种子元素.此处代码省略
      //这里是对property子元素的解析过程,Array、List、Set、Map、Prop等各种元素都会在这里进行解析,生成对应的数据对象,比如ManagedList、ManagedArray、ManagedSet等。这些Managed类是Spring对具体的BeanDefinition的数据封装
    //解析list
       elseif (DomUtils.nodeNameEquals(ele, LIST_ELEMENT)) {
           return parseListElement(ele, bd);
       }
    //解析set
       elseif (DomUtils.nodeNameEquals(ele, SET_ELEMENT)) {
           return parseSetElement(ele, bd);
       }
    //解析map
       elseif (DomUtils.nodeNameEquals(ele, MAP_ELEMENT)) {
           returnparseMapElement(ele, bd);
       }
     //解析props
       elseif (DomUtils.nodeNameEquals(ele, PROPS_ELEMENT)) {
           return parsePropsElement(ele);
       }
           returnnull;
       }
    }
    ①解析list
//【代码清单】解析list
public List parseListElement(Element collectionEle,BeanDefinition bd) {
       String defaultTypeClassName = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
       NodeList nl = collectionEle.getChildNodes();
         //把list数据封装到ManagedList对象
       ManagedList list= new ManagedList(nl.getLength());
       list.setSource(extractSource(collectionEle));
       list.setMergeEnabled(parseMergeAttribute(collectionEle));
        //遍历所有的元素节点,并判断其类型是否为Element
       for (int i = 0; i < nl.getLength(); i++) {
           Node node = nl.item(i);
           if (node instanceof Element && !DomUtils.nodeNameEquals(node,DESCRIPTION_ELEMENT)) {
              //加入到ManagedList,同时触发对下一层子元素的解析过程,       
              //这是一个递归的调用
              list.add(parsePropertySubElement((Element)node, bd, defaultTypeClassName));
           }
       }
       return list;
    }

   这里就是bean标签大致解析过程,解析配置文件,无非就是把配置属性设置到相应的对象中,然后又把对应的对象设置到一个对象中,比如这里的,把bean属性设置到beanDefinition对象上,把ref属性封装到RuntimeBeanReference,vale属性封装到TypedStringValue,map封装到managedMap,list封装到managedList,set封装到managedSet.然后把这些对象设置到beanDefinition对象上。除了设置值,无其他实质性的操作。


二、解析alias标签

protected void processAliasRegistration(Element ele) {

		String name = ele.getAttribute(NAME_ATTRIBUTE);
		  //获取别名
		String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
		boolean valid = true;
		if (!StringUtils.hasText(name)) {
			getReaderContext().error("Name must not be empty", ele);
			valid = false;
		}
		 //判断是否有别名
		if (!StringUtils.hasText(alias)) {
			getReaderContext().error("Alias must not be empty", ele);
			valid = false;
		}
		 //如果有别名
		if (valid) {
	             try {
		getReaderContext().getRegistry().registerAlias(name, alias);
			}
		}
		  //通知封装成功
		getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
		}
	}

        如果有别名,spring会如何封装呢?

	public void registerAlias(String name, String alias) {

		if (alias.equals(name)) {
			this.aliasMap.remove(alias);
		}
		else {
			if (!allowAliasOverriding()) {
			String registeredName = (String) this.aliasMap.get(alias);
	         //如果有别名,以别名为key值,name为value值,保存到一个map中
			this.aliasMap.put(alias, name);
		}
	}

     从这里可以看出,封装alias标签,其实就是把别名和name放到一个map中,建立对应关系。


三、解析import标签

	protected void importBeanDefinitionResource(Element ele) {
	//获取import标签的resouce属性
		String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
		if (!StringUtils.hasText(location)) {

			return;
		}
	
		location = SystemPropertyUtils.resolvePlaceholders(location);
	if (ResourcePatternUtils.isUrl(location)) {
			try {
		Set actualResources = new LinkedHashSet(4);
		int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);		
	Resource[] actResArray = (Resource[]) actualResources.toArray(new Resource[actualResources.size()]);	
			}
		}
		else {
	
		try {
		 //得到resouce对象
	Resource relativeResource = getReaderContext().getResource().createRelative(location);
	//调用loadBeanDefinitions方法
int importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
			}
	
		
		}
	}

     从这里看出,解析import标签,其实也是解析document对象


四。总结

   本篇博文介绍了spring如何解析xml配置中的默认命名空间:把bean标签属性封装到相应的对象,然后把这些对象设置到beanDefinition对象中,跟着又把beanDefinition对象设置到beanDefinitionHolder对象中,最后把beanDefinitionHolder保存到beanFactory的一个map中(把对象放进容器)。下篇博文将介绍解析非默认命名空间。因为解析配置文件,归根到底就是把属性封装到beanDefinition对象中,所以下篇博文将简要介绍几个常用的标签,如aop和transaction.