Spring Ioc核心源码解析

1.关于Ioc容器

        (1)Ioc容器作用

                  最主要是完成了对象的创建和依赖的管理注入等

        (2)换个视角来考虑

                 所谓的控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器帮忙来实现。那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。这个描述最具体的表现就是我们的配置文件。那么就会有以下2个问题:

                      1.对象和对象的关系怎么表示?

                          可以用xml,properties等文件表示

                      2.描述对象关系的文件放在哪里?

                          可能是classpath,fileSystem,或者是URL网络资源,ServletContext等

                  有了配置文件,还需要对配置文件进行解析,解析过程中可能又会遇到以下几个问题

                      1.不同的配置文件对对象的描述不一样,如标准的,自定义声明式的,如何统一?

                          使用Resource接口来统一

                      2.在内部需要有一个统一的关于对象的定义

                          统一使用BeanDefinition

                      3.如何对不同的配置文件进行解析?

                          使用BeanDefinitionReader和BeanFactory

                      4.需要对不同的配置文件语法,采用不同解析方式?

                          使用ApplicationContext

                  以上5个全是接口,都有各式各样的实现,正是这5个接口定义了spring ioc容器的基本代码组件结构,而其组件各种实现的组合关系组成了一个运行时的具体容器。


2.各组件详解

        (1)Resource

                      是对资源的抽象,每一个接口实现类都代表了一种资源类型,如ClasspathResource、URLResource、FileSystemResource等。每一个资源类型都封装了对某一种特定资源的访问策略。它是spring资源访问策略的一个基础实现,应用在很多场景。

                    

        (2)BeanDefinition

                      又来抽象和描述一个具体bean对象。是描述一个bean对象的基本数据结构

        (3)BeanDefinitionReader

                      将外部资源对象描述的bean定义,统一转化为统一个内部数据结构BeanDefinition。对应不同的描述需要有不同的Reader。如XMLBeanDefinitionReader用来读取xml描述配置的bean对象

                    

        (4)BeanFactory

                      用来定义一个很纯粹的bean容器,它是一个bean容器的必备结构。同时和外部应用环境等隔离。BeanDefinition是它的基本数据结构。他维护一个BeanDefinitions Map,并可以根据BeanDefinition的描述进行bean的创建和管理。

                                   


        (5)ApplicationContext

                      从名字上来看叫做应用上下文,是和应用环境息息相关的。这个就是我们平时开发中经常直接使用的一个类,应用上下文,或者也叫做spring容器。其实它的基本实现是会持有一个BeanFactory对象,并基于此提供一些包装和功能扩展。为什么要这么做呢?因为BeanFactory实现了一个容器基本结构和功能,但是与外部环境隔离。那么读取配置文件,并将配置文件解析成BeanDefinition,然后注册到BeanFactory的这一个过程的封装自然就需要ApplicationContext。ApplicationContext和应用环境息息相关,常见的实现类有ClassPathXMLApplicationContext、FileSystemXMLApplicationContext、WebApplicationContext等。ClassPath、xml、FileSystem等词都代表了应用和环境相关的一些意思。

                            


                      以上5个组件基本代表了ioc容器的一个最基本组成,而组件的组合是放在ApplicationContext的实现这一层来完成的

                      以ClassPathXMLApplicationContext为例,展示5个组件的组合关系

                                

3.解析配置文件过程

        (1)基本步骤

                      1)把xml配置文件转换成Resource。

                            Resource的转换时先通过ResourcePatternResolver来解析可识别格式的配置文件的路径(如"classpath:"等),如果没有指定格式,默认会按照类路径的资源来处理。

                      2)利用XMLBeanDefinitionReader完成对xml的解析,将xml Resource中定义的bean对象统一转换成统一的BeanDefinition。

                      3)将BeanDefinition注册到BeanFactory,完成对BeanFactory的初始化。BeanFactory中会维护一个BeanDefinition的Map        

                       (2)详细步骤

                     1)创建一个ClasspathXmlApplicationContext对象,传入文件名称。

ClassPathXmlApplicationContext re = new ClassPathXmlApplicationContext("applicationContext.xml");
                     

                     2)ClasspathXmlApplicationContext中有多个构造方法,但是都会重载到下面的方法

	public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
			throws BeansException 
	{
		super(parent);
		setConfigLocations(configLocations);
		if (refresh) 
		{
			refresh();
		}
	}
                         其中首先设置配置路径(包括Resource路径),然后进行刷新,而这个refresh方法是ioc容器的初始化的入口

                         为什么叫refresh?其实也就是刷新的意思,该ioc容器里面维护了一个单例的BeanFactory,如果bean的配置有修改,也可以直接调用refresh方法,它将销毁之前的BeanFactory,重新创建一个BeanFactory。所以叫refresh也是可以理解的。
                         

                     3)refresh方法由AbstractApplicationContext实现

	public void refresh() throws BeansException, IllegalStateException 
	{
		synchronized (this.startupShutdownMonitor) 
		{
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			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.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) 
			{
				logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}
		}
	}
                       这个方法中描述了ApplicationContext的整个初始化过程,包括BeanFactory的更新,还有messagesource以及一些生命周期有关属性的注册,而我们关心的是BeanFactory的更新,即obtainFreshBeanFactory()方法

                     4)启动对BeanDefinition的载入

                           还是在ApplicationContext类中

	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() 
	{
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) 
		{
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}
                           第一步执行refreshBeanFactory,具体实现在AbstratRefreshableApplicationContext类中

	protected final void refreshBeanFactory() throws BeansException 
	{
		if (hasBeanFactory()) 
		{
			destroyBeans();
			closeBeanFactory();
		}
		try 
		{
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) 
			{
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) 
		{
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}
                        第一步判断是否已经创建过BeanFactory,如果是,将他销毁,重新创建

                        第二步就是创建各种ApplicationContext持有的真正容器实现类DefaultListableBeanFactory,创建ioc容器

                        最后启动BeanDefinition的载入 loadBeanDefinitions(beanFactory)方法       

                     5)BeanFactory将载入工作交给BeanDefinitionReader

                           loadBeanDefinitions(beanFactory)方法是抽象的,又因为我们的配置文件是xml格式的,所以具体实现是在AbstractXmlApplicationContext中

	protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException 
	{
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

		// Configure the bean definition reader with this context's
		// resource loading environment.
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// Allow a subclass to provide custom initialization of the reader,
		// then proceed with actually loading the bean definitions.
		initBeanDefinitionReader(beanDefinitionReader);
		loadBeanDefinitions(beanDefinitionReader);
	}
                  这里创建了一个XMLBeanDefinitionReader对象,它专门用来读取基于xml文件格式的BeanDefinition配置,接下来重载到loadBeanDs(BeanDefinitionReader)

	protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException 
	{
		Resource[] configResources = getConfigResources();
		if (configResources != null) 
		{
			reader.loadBeanDefinitions(configResources);
		}
		String[] configLocations = getConfigLocations();
		if (configLocations != null) 
		{
			reader.loadBeanDefinitions(configLocations);
		}
	}
                  首先载入Resource对象用来定位资源,Resource对象的生成在ClassPathXmlApplicationContext中setConfigLocations(configLocations)方法实现,然后调用XMLBeanDefinitionReader基类的AbstractBeanDefinitionReader的loadBeanDefinitions方法。

	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;
	}
                 然后调用loadBeanDefinitions(resource)方法,此方法的具体实现在XMLBeanDefinitionReader中

	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException 
	{
		return loadBeanDefinitions(new EncodedResource(resource));
	}
                会重载到loadBeanDefinitionsloadBeanDefinitions(EncodeResource)

	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<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
		if (currentResources == null) 
		{
			currentResources = new HashSet<EncodedResource>(4);
			this.resourcesCurrentlyBeingLoaded.set(currentResources);
		}
		if (!currentResources.add(encodedResource)) 
		{
			throw new BeanDefinitionStoreException(
					"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
		}
		try 
		{
			InputStream inputStream = encodedResource.getResource().getInputStream();
			try 
			{
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null)
				{
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
			}
			finally 
			{
				inputStream.close();
			}
		}
		catch (IOException ex) 
		{
			throw new BeanDefinitionStoreException(
					"IOException parsing XML document from " + encodedResource.getResource(), ex);
		}
		finally 
		{
			currentResources.remove(encodedResource);
			if (currentResources.isEmpty()) 
			{
				this.resourcesCurrentlyBeingLoaded.remove();
			}
		}
	}
                此方法主要是对输入流进行编码操作,然后调用doLoadBeanDefinitions()方法


                     6)XMLBeanDefinitionReader将载入工作交给W3C的dom

                           因为读入的文件是xml格式的,所以底层的实现肯定是要和W3C的dom打交道

    /**
	 * Actually load bean definitions from the specified XML file.
	 * @param inputSource the SAX InputSource to read from
	 * @param resource the resource descriptor for the XML file
	 * @return the number of bean definitions found
	 * @throws BeanDefinitionStoreException in case of loading or parsing errors
	 */
	protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException 
			{
		try 
		{
			int validationMode = getValidationModeForResource(resource);
			Document doc = this.documentLoader.loadDocument(
					inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
			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);
		}
	}
               在此方法中生成了一个Document类的对象,下一步是进行对象的注册,registerBeanDefinitions(doc,resource)方法

	/**
	 * Register the bean definitions contained in the given DOM document.
	 * @param doc the DOM document
	 * @param resource the resource descriptor (for context information)
	 * @return the number of bean definitions found
	 * @throws BeanDefinitionStoreException in case of parsing errors
	 */
	@SuppressWarnings("deprecation")
	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException 
	{
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		documentReader.setEnvironment(getEnvironment());
		int countBefore = getRegistry().getBeanDefinitionCount();
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}
               此方法统计了注册的BeanDefinition的数量,返回一个int值,而具体的注册工作在BeanDefinitionDocumentReader接口的实现类DefaultBeanDefinitionDocumentReader中registerBeanDefinitions()中实现


                     7)BeanDefinitionDocumentReader将载入工作交给代理类BeanDefinitionParserDelegate    

	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) 
	{
		this.readerContext = readerContext;
		logger.debug("Loading bean definitions");
		Element root = doc.getDocumentElement();
		doRegisterBeanDefinitions(root);
	}
                首先得到dom结构的根,然后由根进行分析

	/**
	 * Register each bean definition within the given root {@code <beans/>} element.
	 */
	protected void doRegisterBeanDefinitions(Element root) 
	{
		String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
		if (StringUtils.hasText(profileSpec)) 
		{
			String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
					profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			if (!getEnvironment().acceptsProfiles(specifiedProfiles)) 
			{
				return;
			}
		}

		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(this.readerContext, root, parent);

		preProcessXml(root);
		parseBeanDefinitions(root, this.delegate);
		postProcessXml(root);

		this.delegate = parent;
	}
                通过parseBeanDefinitions方法对root下面的结构开始解析

	/**
	 * Parse the elements at the root level in the document:
	 * "import", "alias", "bean".
	 * @param root the DOM root element of the document
	 */
	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);
		}
	}
                查看其中最重要的parseDefaultElement()方法

	private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 
	{
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) 
		{
			importBeanDefinitionResource(ele);
		}
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) 
		{
			processAliasRegistration(ele);
		}
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) 
		{
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) 
		{
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}
                从这个方法就可以看出底层元素的端倪了,首先判断Node是否为import节点,然后是alias节点,最后是bean节点,我们关心的是bean节点,查看processBeanDefinition()方法
	protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
	{
		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));
		}
	}
                这里首先由BeanDefinitionParserDelegate生成BeanDefinition的包装类BeanDefinitionHolder,然后再进行一些修饰工作,这里把工作正式交给BeanDefinitionParserDelegate。

                以下就是一些xml的解析工作。


                    8)BeanDefinition的解析主要在BeanDefinitionParserDelegate的ParserBeanDefinitionElement()方法中进行

	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) 
	{
		String id = ele.getAttribute(ID_ATTRIBUTE);
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

		List<String> aliases = new ArrayList<String>();
		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) && !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);
		}

		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 &&
								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 (Exception ex) 
				{
					error(ex.getMessage(), ele);
					return null;
				}
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}
                这个方法首先得到元素的name和id以及别名属性,然后再生成底层的AbstractBeanDefinition对象将他们包装成BeanDefinitionHolder,其中包括bean的名称、姓名、以及BeanDefinition,返回给上层方法,核心在于生成BeanDefinition的parseBeanDefinitionElement()方法

	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, BeanDefinition containingBean) 
	{

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

		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);
			}
			AbstractBeanDefinition bd = 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));

			return bd;
		}
		catch (ClassNotFoundException ex) 
		{
			error("Bean class [" + className + "] not found", ele, ex);
		}
		catch (NoClassDefFoundError err) 
		{
			error("Class that bean class [" + className + "] depends on not found", ele, err);
		}
		catch (Throwable ex) 
		{
			error("Unexpected failure during bean definition parsing", ele, ex);
		}
		finally 
		{
			this.parseState.pop();
		}

		return null;
	}
                这个方法全部都是bean节点中的配置信息。首先得到class的名字,然后得到继承的parent的名字,然后是meta节点,look-up节点,replace-method节点,构造函数设置节点,最后是比较复杂的property节点。我们继续分析比较复杂的property节点的解析,parsePropertyElement()方法

	/**
	 * Parse property sub-elements of the given bean element.
	 */
	public void parsePropertyElements(Element beanEle, BeanDefinition bd)
	{
		NodeList nl = beanEle.getChildNodes();
		for (int i = 0; i < nl.getLength(); i++) 
		{
			Node node = nl.item(i);
			if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) 
			{
				parsePropertyElement((Element) node, bd);
			}
		}
	}
                将bean节点的子元素逐个取出判断是否为property节点,然后进行解析,parsePropertyElement()方法

	/**
	 * Parse a property element.
	 */
	public void parsePropertyElement(Element ele, BeanDefinition bd) 
	{
		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 
		{
			if (bd.getPropertyValues().contains(propertyName))
			{
				error("Multiple 'property' definitions for property '" + propertyName + "'", ele);
				return;
			}
			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节点内部进行解析,最后加入到bean节点信息中,我们继续解析property节点内部,parsePropertyValue()方法

	/**
	 * Get the value of a property element. May be a list etc.
	 * Also used for constructor arguments, "propertyName" being null in this case.
	 */
	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 < nl.getLength(); i++) 
		{
			Node node = nl.item(i);
			if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
					!nodeNameEquals(node, META_ELEMENT)) 
			{
				// Child element is what we're looking for.
				if (subElement != null) 
				{
					error(elementName + " must not contain more than one sub-element", ele);
				}
				else 
				{
					subElement = (Element) node;
				}
			}
		}

		boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
		boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
		if ((hasRefAttribute && hasValueAttribute) ||
				((hasRefAttribute || hasValueAttribute) && subElement != null)) 
		{
			error(elementName +
					" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
		}

		if (hasRefAttribute) 
		{
			String refName = ele.getAttribute(REF_ATTRIBUTE);
			if (!StringUtils.hasText(refName)) 
			{
				error(elementName + " contains empty 'ref' attribute", ele);
			}
			RuntimeBeanReference ref = new RuntimeBeanReference(refName);
			ref.setSource(extractSource(ele));
			return ref;
		}
		else if (hasValueAttribute) 
		{
			TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
			valueHolder.setSource(extractSource(ele));
			return valueHolder;
		}
		else if (subElement != null)
        {
			return parsePropertySubElement(subElement, bd);
		}
		else 
		{
			// Neither child element nor "ref" or "value" attribute found.
			error(elementName + " must specify a ref or value", ele);
			return null;
		}
	}
                property节点主要是value和ref属性的配置,所以此方法首先是配置以上两个属性,然后是分析property节点的子元素,parsePropertySubElement()方法

	/**
	 * Parse a value, ref or collection sub-element of a property or
	 * constructor-arg element.
	 * @param ele subelement of property element; we don't know which yet
	 * @param defaultValueType the default type (class name) for any
	 * {@code <value>} tag that might be created
	 */
	public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) 
	{
		if (!isDefaultNamespace(ele)) 
		{
			return parseNestedCustomElement(ele, bd);
		}
		else if (nodeNameEquals(ele, BEAN_ELEMENT)) 
		{
			BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
			if (nestedBd != null) 
			{
				nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
			}
			return nestedBd;
		}
		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;
		}
		else if (nodeNameEquals(ele, IDREF_ELEMENT)) 
		{
			return parseIdRefElement(ele);
		}
		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;
		}
		else if (nodeNameEquals(ele, ARRAY_ELEMENT)) 
		{
			return parseArrayElement(ele, bd);
		}
		else if (nodeNameEquals(ele, LIST_ELEMENT)) 
		{
			return parseListElement(ele, bd);
		}
		else if (nodeNameEquals(ele, SET_ELEMENT)) 
		{
			return parseSetElement(ele, bd);
		}
		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;
		}
	}
                这个方法首先配置property节点的内嵌bean,然后配置ref引用,然后是idref引用,接下来是内嵌的value元素,还有null元素,最后是一系列的复杂数据结构,array,list,set,map以及props


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值