zoukankan      html  css  js  c++  java
  • BeanDefinition的载入和解析

    概念

    第二个过程是BeanDefinition的载入。这个载入过程是把用户定义好的Bean表示成IoC容器内部的数据结构,而这个容器内部的数据结构就是BeanDefinition。具体来说,这个BeanDefinition实际上就是POJO对象在IoC容器中的抽象,通过这个BeanDefinition定义的数据结构,使IoC容器能够方便地对POJO对象也就是Bean进行管理。IoC容器对Bean的管理和依赖注入功能的实现,就是通过对持有的BeanDefinition进行各种相关操作完成的。


    分析过程

    • 整个载入和解析过程也是从refresh()启动的,该方法在FileSystemXmlApplicationContext的基类AbstractApplic-ationContext中实现,它详细的描述了整个ApplicationContext的初始化过程,比如BeanFactory的更新,Mess-ageSource和PostProcessor的注册,等等。这里看起来更像是对ApplicationContext进行初始化的模板或执行提纲,这个执行过程为Bean的生命周期管理提供了条件。

    public void refresh() throws BeansException, IllegalStateException {
    		synchronized (this.startupShutdownMonitor) {
    			// Prepare this context for refreshing.
    			prepareRefresh();
    
    		// Tell the subclass to refresh the internal bean factory.
      //这里是在子类中启动refreshBeanFactory()的地方,也就是创建实际BeanFactory的方法入口
    		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    
    		// Prepare the bean factory for use in this context.
    		prepareBeanFactory(beanFactory);
    
    		try {
    			// Allows post-processing of the bean factory in context subclasses.
        //设置BeanFactory的后置处理
    			postProcessBeanFactory(beanFactory);
    
    			// Invoke factory processors registered as beans in the context.
        //调用BeanFactory的后处理器.这些后处理器是在Bean定义中向容器注册的
    			invokeBeanFactoryPostProcessors(beanFactory);
    
    			// Register bean processors that intercept bean creation.
        //注册Bean的后处理器,在Bean创建过程中调用。
    			registerBeanPostProcessors(beanFactory);
    
    			// Initialize message source for this context.、
        //对上下文中的消息源进行初始化
    			initMessageSource();
    
    			// Initialize event multicaster for this context.
        //初始化上下文中的事件机制
    			initApplicationEventMulticaster();
    
    			// Initialize other special beans in specific context subclasses.
        //初始化其他的特殊Bean
    			onRefresh();
    
    			// Check for listener beans and register them.
        //检查监听Bean并且将这些Bean向容器注册
    			registerListeners();
    
    			// Instantiate all remaining (non-lazy-init) singletons.
        //实例化所有的(non-lazy-init)单件
    			finishBeanFactoryInitialization(beanFactory);
    
    			// Last step: publish corresponding event.
        //发布容器事件.结束Refresh过程
    			finishRefresh();
    		}
    
    		catch (BeansException ex) {
    			// Destroy already created singletons to avoid dangling resources.
        //为防止Bean资源占用,在异常处理中,销毁已经在前面过程中生成的单间Bean
    			destroyBeans();
    
    			// Reset 'active' flag.
    			cancelRefresh(ex);
    
    			// Propagate exception to caller.
    			throw ex;
    		}
    	}
    }</code></pre>
    


    • 之后就进行资源定位过程,定位完成后就开始载入过程(见图一),因为之前创建好DefaultListBeanFactory后,将其“绑定”给XmlBeanDefinitionReader,由XmlBeanDefinitionReader继续后续的定位和载入(图二),所以这里的载入过程也由XmlBeanDefinitionReader来完成。需要注意的是,因为这里我们使用XML方式定义Bean,所以使用XmlBeanDefinitionReader来处理,如果使用了其他定义方式,就需要使用其他种类的BeanDefinitionReader来完成载入工作。

    image.png


    image.png


    • 这里调用的是loadBeanDefinitions(Resource res)方法,但这个方法在AbstractBeanDefinitionReader类里是没有实现的,它是一个接口方法,具体的实现在XmlBeanDefinitionReader中。在读取器中,需要得到代表XML文件的Resource,因为这个Resource对象封装了对XML文件的I/O操作,所以读取器可以在打开I/O流后得到 XML的文件对象。有了这个文件对象以后,就可以按照Spring的Bean定义规则来对这个XML的文档树进行解析。

    //父类AbstractBeanDefinitionReader遍历调用loadBeanDefinitions(resource)
    public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
    		Assert.notNull(resources, "Resource array must not be null");
    		int counter = 0;
    		for (Resource resource : resources) {
    			counter += loadBeanDefinitions(resource);
    		}
    		return counter;
    }
    

    //子类XmlBeanDefinitionReader对loadBeanDefinitions(Resource resource)的具体实现
    public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
    return loadBeanDefinitions(new EncodedResource(resource));
    }

    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
    Assert.notNull(encodedResource, "EncodedResource must not be null");
    if (logger.isInfoEnabled()) {
    logger.info("Loading XML bean definitions from " + encodedResource.getResource());
    }

    	Set&lt;EncodedResource&gt; currentResources = this.resourcesCurrentlyBeingLoaded.get();
    	if (currentResources == null) {
    		currentResources = new HashSet&lt;EncodedResource&gt;(4);
    		this.resourcesCurrentlyBeingLoaded.set(currentResources);
    	}
    	if (!currentResources.add(encodedResource)) {
    		throw new BeanDefinitionStoreException(
    				&quot;Detected cyclic loading of &quot; + encodedResource + &quot; - check your import definitions!&quot;);
    	}
    //这里得到XML文件,并得到IO的InputSource准备进行读取
    	try {
    		InputStream inputStream = encodedResource.getResource().getInputStream();
    		try {
    			InputSource inputSource = new InputSource(inputStream);
    			if (encodedResource.getEncoding() != null) {
    				inputSource.setEncoding(encodedResource.getEncoding());
    			}
        //具体的读取过程在doLoadBeanDefinitions中,是从特定的XML文件中实际载入的地方。
    			return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
    		}
    		finally {
    			inputStream.close();
    		}
    	}
    	catch (IOException ex) {
    		throw new BeanDefinitionStoreException(
    				&quot;IOException parsing XML document from &quot; + encodedResource.getResource(), ex);
    	}
    	finally {
    		currentResources.remove(encodedResource);
    		if (currentResources.isEmpty()) {
    			this.resourcesCurrentlyBeingLoaded.remove();
    		}
    	}
    

    }

    //子类XmlBeanDefinitionReader的doLoadBeanDefinitions方法
    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
    throws BeanDefinitionStoreException {
    try {
    int validationMode = getValidationModeForResource(resource);
    //这里取得XML的Document对象,如何获得可详细看源码。
    Document doc = this.documentLoader.loadDocument(
    inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
    //这里启动对BeanDefinition解析的详细过程,这个解析会使用到Spring的Bean配置规则
    return registerBeanDefinitions(doc, resource);
    }
    catch (BeanDefinitionStoreException ex) {
    throw ex;
    }
    catch (SAXParseException ex) {
    throw new XmlBeanDefinitionStoreException(resource.getDescription(),
    "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
    }
    catch (SAXException ex) {
    throw new XmlBeanDefinitionStoreException(resource.getDescription(),
    "XML document from " + resource + " is invalid", ex);
    }
    catch (ParserConfigurationException ex) {
    throw new BeanDefinitionStoreException(resource.getDescription(),
    "Parser configuration exception parsing XML from " + resource, ex);
    }
    catch (IOException ex) {
    throw new BeanDefinitionStoreException(resource.getDescription(),
    "IOException parsing XML document from " + resource, ex);
    }
    catch (Throwable ex) {
    throw new BeanDefinitionStoreException(resource.getDescription(),
    "Unexpected exception parsing XML document from " + resource, ex);
    }
    }

    //子类XmlBeanDefinitionReader的registerBeanDefinitions方法
    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    //得到BeanDefinitionDocumentReader来对XML进行解析
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    documentReader.setEnvironment(this.getEnvironment());
    int countBefore = getRegistry().getBeanDefinitionCount();
    //具体的解析过程在BeanDefinitionDocumentReader的registerBeanDefinitions中完成。
    //createReaderContext(resource)返回一个ReaderContext对象,里面封装了XmlBeanDefinitionReader等组件。
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    return getRegistry().getBeanDefinitionCount() - countBefore;
    }


    • BeanDefinition的载入分成两部分,首先通过调用XML的解析器得到document对象,但这些document对象并没有按照Spring的Bean规则进行解析。在完成通用的XML解析以后,才是按照Spring的Bean规则进行解析的地方,这个按照Spring的Bean规则进行解析的过程是在documentReader中实现的。这里使用的documentReader是默认设置好的DefaultBeanDefinitionDocumentReader。然后就完成BeanDefinition的处理,处理的结果由Bean-DefinitionHolder对象来持有。这个BeanDefinitionHolder除了持有BeanDefinition对象外,还持有其他与Bean-Definition的使用相关的信息,比如Bean的名字、别名集合等。这个BeanDefinitionHolder的生成是通过对Docu-ment文档树的内容进行解析来完成的,可以看到这个解析过程是由BeanDefinitionParserDelegate来实现(具体在processBeanDefinition方法中实现)的,同时这个解析是与Spring对BeanDefinition的配置规则紧密相关的。具体的实现原理如下代码:

    //DefaultBeanDefinitionDocumentReader中的registerBeanDefinitions方法
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        //将封装了XmlBeanDefinitionReader等组件的XmlReaderContext传给DefaultBeanDefinitionDocumentReader,方便后续回调。
    		this.readerContext = readerContext;
    
    	logger.debug(&quot;Loading bean definitions&quot;);
    	Element root = doc.getDocumentElement();
    
    	doRegisterBeanDefinitions(root);
    

    }

    //DefaultBeanDefinitionDocumentReader中的doRegisterBeanDefinitions方法
    protected void doRegisterBeanDefinitions(Element root) {
    String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
    if (StringUtils.hasText(profileSpec)) {
    Assert.state(this.environment != null, "environment property must not be null");
    String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
    if (!this.environment.acceptsProfiles(specifiedProfiles)) {
    return;
    }
    }

    	// any nested &lt;beans&gt; elements will cause recursion in this method. In
    	// order to propagate and preserve &lt;beans&gt; default-* attributes correctly,
    	// keep track of the current (parent) delegate, which may be null. Create
    	// the new (child) delegate with a reference to the parent for fallback purposes,
    	// then ultimately reset this.delegate back to its original (parent) reference.
    	// this behavior emulates a stack of delegates without actually necessitating one.
    //对文档进行解析的实际作用类BeanDefinitionParserDelegate
    	BeanDefinitionParserDelegate parent = this.delegate;
    	this.delegate = createHelper(readerContext, root, parent);
    
    	preProcessXml(root);
    //利用BeanDefinitionParserDelegate进行解析的入口方法
    	parseBeanDefinitions(root, this.delegate);
    	postProcessXml(root);
    
    	this.delegate = parent;
    

    }

    //DefaultBeanDefinitionDocumentReader中的parseBeanDefinitions方法
    //遍历子节点,也就是XML文件中的标签,依次解析
    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    if (delegate.isDefaultNamespace(root)) {
    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;
    if (delegate.isDefaultNamespace(ele)) {
    parseDefaultElement(ele, delegate);
    }
    else {
    delegate.parseCustomElement(ele);
    }
    }
    }
    }
    else {
    delegate.parseCustomElement(root);
    }
    }

    //DefaultBeanDefinitionDocumentReader中的parseDefaultElement方法
    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    //对"import"标签进行处理
    if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
    importBeanDefinitionResource(ele);
    }
    //对"alias"标签进行处理
    else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
    processAliasRegistration(ele);
    }
    //对"bean"标签进行处理,是主要的解析标签。
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
    processBeanDefinition(ele, delegate);
    }
    //对"beans"标签进行处理
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
    // recurse
    doRegisterBeanDefinitions(ele);
    }
    }

    //DefaultBeanDefinitionDocumentReader中的processBeanDefinition方法
    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    //由BeanDefinitionParserDelegate负责解析,BeanDefinitionHolder是BeanDefinition的
    //封装类,用于完成向IoC容器的注册
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
    bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
    try {
    // Register the final decorated instance.
    //载入解析完,注册的入口函数
    BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
    }
    catch (BeanDefinitionStoreException ex) {
    getReaderContext().error("Failed to register bean definition with name '" +
    bdHolder.getBeanName() + "'", ele, ex);
    }
    // Send registration event.
    getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
    }


    • 具体的Spring BeanDefinition的解析是在BeanDefinitionParserDelegate中完成的。这个类里包含了对各种Spri-ngBean定义规则的处理,感兴趣可以仔细研究。比如我们最熟悉的对Bean元素的处理是怎样完成的,也就是怎样处理在XML定义文件中出现的<bean></bean>这个最常见的元素信息。在这里会看到对那些熟悉的Bean定义的处理,比如id, name, aliase等属性元素。把这些元素的值从XML文件相应的元素的属性中读取出来以后,设置到生成的BeanDefinitionHolder中去。这些属性的解析还是比较简单的。对于其他元素配置的解析,比如各种Bean的属性配置,通过一个较为复杂的解析过程,这个过程是由parseBeanDefinitionElement来完成的。解析完成以后。会把解析结果放到BeanDefinition对象中并设置到BeanDefinitionHolder中去。具体代码如下:

    //BeanDefinitionParserDelegate中的parseBeanDefinitionElement方法。
    //这里ele是<bean>标签,BeanDefinition可以看成是对<bean>定义的抽象,也就是存储<bean>定义的数据结构,
    //里面封装的数据大多都是跟<bean>相关的,比如init-method,destroy-method等等,具体可以查看源码,有了
    //这些数据,IoC才能对Bean配置进行处理。
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
    	  //这里取得在<bean>元素中定义的id,name和aliaes属性的值	
        String id = ele.getAttribute(ID_ATTRIBUTE);
    		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
    
    	List&lt;String&gt; aliases = new ArrayList&lt;String&gt;();
    	if (StringUtils.hasLength(nameAttr)) {
    		String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
    		aliases.addAll(Arrays.asList(nameArr));
    	}
    
    	String beanName = id;
    	if (!StringUtils.hasText(beanName) &amp;&amp; !aliases.isEmpty()) {
    		beanName = aliases.remove(0);
    		if (logger.isDebugEnabled()) {
    			logger.debug(&quot;No XML 'id' specified - using '&quot; + beanName +
    					&quot;' as bean name and &quot; + aliases + &quot; as aliases&quot;);
    		}
    	}
    
    	if (containingBean == null) {
    		checkNameUniqueness(beanName, aliases, ele);
    	}
    
    //这里引发对Bean元素的详细解析
    	AbstractBeanDefinition beanDefinition = 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);
    					// Register an alias for the plain bean class name, if still possible,
    					// if the generator returned the class name plus a suffix.
    					// This is expected for Spring 1.2/2.0 backwards compatibility.
    					String beanClassName = beanDefinition.getBeanClassName();
    					if (beanClassName != null &amp;&amp;
    							beanName.startsWith(beanClassName) &amp;&amp; beanName.length() &gt; beanClassName.length() &amp;&amp;
    							!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
    						aliases.add(beanClassName);
    					}
    				}
    				if (logger.isDebugEnabled()) {
    					logger.debug(&quot;Neither XML 'id' nor 'name' specified - &quot; +
    							&quot;using generated bean name [&quot; + beanName + &quot;]&quot;);
    				}
    			}
    			catch (Exception ex) {
    				error(ex.getMessage(), ele);
    				return null;
    			}
    		}
    		String[] aliasesArray = StringUtils.toStringArray(aliases);
    		return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    	}
    
    	return null;
    

    }

    //BeanDefinitionParserDelegate中的parseBeanDefinitionElement方法
    public AbstractBeanDefinition parseBeanDefinitionElement(
    Element ele, String beanName, BeanDefinition containingBean) {

    	this.parseState.push(new BeanEntry(beanName));
    //这里只读取定义的&lt;bean&gt;中设里的class名字.然后载入到BeanDefiniton中去,只是做个
    //记录.并不涉及对象的实例化过程,对象的实例化实际上是在依核注入时完成的
    	String className = null;
    	if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
    		className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
    	}
    
    	try {
    		String parent = null;
    		if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
    			parent = ele.getAttribute(PARENT_ATTRIBUTE);
    		}
      //这里生成需要的BeanDefinition对象,为Bean定义信息的载入做准备
    		AbstractBeanDefinition bd = createBeanDefinition(className, parent);
      
      //这里对当前的Bean元素进行属性解析.并设里description的信息
    		parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
    		bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
      
      //从名字可以清楚地看到.这里是对各种&lt;bean&gt;元素的信息进行解析的地方
    		parseMetaElements(ele, bd);
    		parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
    		parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
      
      //解析&lt;bean&gt;的构造函数设置
    		parseConstructorArgElements(ele, bd);
      //解析&lt;bean&gt;的property设置
    		parsePropertyElements(ele, bd);
    		parseQualifierElements(ele, bd);
    
    		bd.setResource(this.readerContext.getResource());
    		bd.setSource(extractSource(ele));
    
    		return bd;
    	}
    //下面这些异常是在配JBean出现问题时经常会看到的,这些检查是在createBeanDefinition
    //时进行的,会检查Bean的class设置是否正确,比如这个类是否能找到。
    	catch (ClassNotFoundException ex) {
    		error(&quot;Bean class [&quot; + className + &quot;] not found&quot;, ele, ex);
    	}
    	catch (NoClassDefFoundError err) {
    		error(&quot;Class that bean class [&quot; + className + &quot;] depends on not found&quot;, ele, err);
    	}
    	catch (Throwable ex) {
    		error(&quot;Unexpected failure during bean definition parsing&quot;, ele, ex);
    	}
    	finally {
    		this.parseState.pop();
    	}
    
    	return null;
    }</code></pre>
    


    • 上面是具体生成BeanDefinition的地方。在这里,我们举一个对property进行解析的例子来完成对整个BeanDefi-nition载入过程的分析,还是在类BeanDefinitionParserDelegate的代码中,一层一层地对BeanDefinition中的定义进行解析,比如从属性元素集合到具体的每一个属性元素,然后才是对具体的属性值的处理。根据解析结果,对这些属性值的处理会被封装成PropertyValue对象并设置到BeanDefinition对象中去,代码如下:

    //BeanDefinitionParserDelegate中的parsePropertyElements方法
    public void parsePropertyElements(Element beanEle, BeanDefinition bd) {
        //遍历所有Bean元素下定义得到property元素
    		NodeList nl = beanEle.getChildNodes();
    		for (int i = 0; i < nl.getLength(); i++) {
    			Node node = nl.item(i);
    			if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {
            //在判断是property元素后对该property元素进行解析的过程
    				parsePropertyElement((Element) node, bd);
    			}
    		}
    	}
    

    //BeanDefinitionParserDelegate中的parsePropertyElement方法
    public void parsePropertyElement(Element ele, BeanDefinition bd) {
    //取得property的名字
    String propertyName = ele.getAttribute(NAME_ATTRIBUTE);
    if (!StringUtils.hasLength(propertyName)) {
    error("Tag 'property' must have a 'name' attribute", ele);
    return;
    }
    this.parseState.push(new PropertyEntry(propertyName));
    try {
    //如果同一个Bean中已经有同名的property存在,则不进行解析。直接返回。也就是说.
    //如果在同一个Bean中有同名的proper七y设里,那么起作用的只是第一个
    if (bd.getPropertyValues().contains(propertyName)) {
    error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
    return;
    }
    //这里是解析property值的地方,这个解析结果会在下面封装到PropertyValue对象中。
    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();
    }
    }

    //BeanDefinitionParserDelegate中的parsePropertyValue方法
    //这里获取property元素的值,也许是一个list或者其他
    public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
    String elementName = (propertyName != null) ?
    "<property> element for property '" + propertyName + "'" :
    "<constructor-arg> element";

    	// Should only have one child element: ref, value, list, etc.
    	NodeList nl = ele.getChildNodes();
    	Element subElement = null;
    	for (int i = 0; i &lt; nl.getLength(); i++) {
    		Node node = nl.item(i);
    		if (node instanceof Element &amp;&amp; !nodeNameEquals(node, DESCRIPTION_ELEMENT) &amp;&amp;
    				!nodeNameEquals(node, META_ELEMENT)) {
    			// Child element is what we're looking for.
    			if (subElement != null) {
    				error(elementName + &quot; must not contain more than one sub-element&quot;, ele);
    			}
    			else {
    				subElement = (Element) node;
    			}
    		}
    	}
    
    //这里判断property的属性是ref还是value,不允许同时是ref和value
    	boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
    	boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
    	if ((hasRefAttribute &amp;&amp; hasValueAttribute) ||
    			((hasRefAttribute || hasValueAttribute) &amp;&amp; subElement != null)) {
    		error(elementName +
    				&quot; is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element&quot;, ele);
    	}
    
    //如果是ref,创建一个ref的数据对象RuntimeBeanReference,这个对象封装了ref的信息
    	if (hasRefAttribute) {
    		String refName = ele.getAttribute(REF_ATTRIBUTE);
    		if (!StringUtils.hasText(refName)) {
    			error(elementName + &quot; contains empty 'ref' attribute&quot;, ele);
    		}
    		RuntimeBeanReference ref = new RuntimeBeanReference(refName);
    		ref.setSource(extractSource(ele));
    		return ref;
    	}
    //如果是value,创建一个value的数据对象TypedStringValue,这个对象封装了value的信息
    	else if (hasValueAttribute) {
    		TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
    		valueHolder.setSource(extractSource(ele));
    		return valueHolder;
    	}
    //如果是子元素,例如list,set等等,则对子元素进行解析
    	else if (subElement != null) {
    		return parsePropertySubElement(subElement, bd);
    	}
    	else {
    		// Neither child element nor &quot;ref&quot; or &quot;value&quot; attribute found.
    		error(elementName + &quot; must specify a ref or value&quot;, ele);
    		return null;
    	}
    }</code></pre>
    


    • 这里我们看看对子元素的解析过程,具体是分析对list标签的解析过程。其他标签的解析可阅读源码。代码如下:

    //BeanDefinitionParserDelegate中的parsePropertySubElement方法,对property的子标签进行解析
    public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
    		if (!isDefaultNamespace(ele)) {
    			return parseNestedCustomElement(ele, bd);
    		}
        //子标签为bean的解析
    		else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
    			BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
    			if (nestedBd != null) {
    				nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
    			}
    			return nestedBd;
    		}
        //子标签为ref的解析
    		else if (nodeNameEquals(ele, REF_ELEMENT)) {
    			// A generic reference to any name of any bean.
    			String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
    			boolean toParent = false;
    			if (!StringUtils.hasLength(refName)) {
    				// A reference to the id of another bean in the same XML file.
    				refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
    				if (!StringUtils.hasLength(refName)) {
    					// A reference to the id of another bean in a parent context.
    					refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
    					toParent = true;
    					if (!StringUtils.hasLength(refName)) {
    						error("'bean', 'local' or 'parent' is required for <ref> element", ele);
    						return null;
    					}
    				}
    			}
    			if (!StringUtils.hasText(refName)) {
    				error("<ref> element contains empty target attribute", ele);
    				return null;
    			}
    			RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
    			ref.setSource(extractSource(ele));
    			return ref;
    		}
        //子标签为idref的解析
    		else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
    			return parseIdRefElement(ele);
    		}
        //子标签为value的解析
    		else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
    			return parseValueElement(ele, defaultValueType);
    		}
    		else if (nodeNameEquals(ele, NULL_ELEMENT)) {
    			// It's a distinguished null value. Let's wrap it in a TypedStringValue
    			// object in order to preserve the source location.
    			TypedStringValue nullHolder = new TypedStringValue(null);
    			nullHolder.setSource(extractSource(ele));
    			return nullHolder;
    		}
        //子标签为array的解析
    		else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
    			return parseArrayElement(ele, bd);
    		}
        //子标签为list的解析
    		else if (nodeNameEquals(ele, LIST_ELEMENT)) {
    			return parseListElement(ele, bd);
    		}
        //子标签为set的解析
    		else if (nodeNameEquals(ele, SET_ELEMENT)) {
    			return parseSetElement(ele, bd);
    		}
        //子标签为map的解析
    		else if (nodeNameEquals(ele, MAP_ELEMENT)) {
    			return parseMapElement(ele, bd);
    		}
    		else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
    			return parsePropsElement(ele);
    		}
    		else {
    			error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
    			return null;
    		}
    	}
    

    //BeanDefinitionParserDelegate中的parseListElement方法,解析list标签,将解析结果封装在ManagedList中。
    public List parseListElement(Element collectionEle, BeanDefinition bd) {
    String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);
    NodeList nl = collectionEle.getChildNodes();
    ManagedList<Object> target = new ManagedList<Object>(nl.getLength());
    target.setSource(extractSource(collectionEle));
    target.setElementTypeName(defaultElementType);
    target.setMergeEnabled(parseMergeAttribute(collectionEle));
    //开始解析list下的标签
    parseCollectionElements(nl, target, bd, defaultElementType);
    return target;
    }

    protected void parseCollectionElements(
    NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) {

    	for (int i = 0; i &lt; elementNodes.getLength(); i++) {
    		Node node = elementNodes.item(i);
    		if (node instanceof Element &amp;&amp; !nodeNameEquals(node, DESCRIPTION_ELEMENT)) {
        //加入到target中,target是一个ManagedList,同时开始对下一层子元素的解析过程。是一个递归调用。
    			target.add(parsePropertySubElement((Element) node, bd, defaultElementType));
    		}
    	}
    }
    


    • 经过这样逐层地解析,我们在XML文件中定义的Bean信息就被整个载入到了IoC容器中,并在容器中建立了数据映射。在IoC容器中建立了对应的数据结构,或者说可以看成是POJO对象在IoC容器中的抽象,这些数据结构可以以AbstractBeanDefinition为入口,让IoC容器执行索引、查询和操作。但是,重要的依赖注入实际上在这个时候还没有发生,现在,在IoC容器BeanDefinition中存在的还只是一些静态的配置信息。严格地说,这时候的容器还没有完全起作用。要发挥容器的作用,还需要完成数据向容器的注册。
  • 相关阅读:
    Docker容器启动时初始化Mysql数据库
    使用Buildpacks高效构建Docker镜像
    Mybatis 强大的结果集映射器resultMap
    Java 集合排序策略接口 Comparator
    Spring MVC 函数式编程进阶
    换一种方式编写 Spring MVC 接口
    【asp.net core 系列】6 实战之 一个项目的完整结构
    【asp.net core 系列】5 布局页和静态资源
    【asp.net core 系列】4. 更高更强的路由
    【Java Spring Cloud 实战之路】- 使用Nacos和网关中心的创建
  • 原文地址:https://www.cnblogs.com/huangzefeng/p/10322411.html
Copyright © 2011-2022 走看看