`

主题:Spring源码浅析 -- XML配置文件的载入与解析

 
阅读更多

原文:http://www.iteye.com/topic/743997

最近在看Spring源代码,对配置文件信息的载入是使用Spring的第一步 ,而这第一步就是一个非常复杂的过程....
Spring通过定义BeanDefination来管理Ioc中的各种对象以及它们之间的依赖关系,所以载入的过程其实就是将XML文件读取并解析成BeanDefination数据的过程。
我们以最常使用的ClassPathXmlApplicationContext为切入点

1. 创建一个ClassPathXmlApplicationContext对象,传入文件路径

  

Java代码 复制代码 收藏代码
  1. ClassPathXmlApplicationContext re = new ClassPathXmlApplicationContext("applicationContext.xml");  
ClassPathXmlApplicationContext re = new ClassPathXmlApplicationContext("applicationContext.xml");

这个构造方法会重载到

Java代码 复制代码 收藏代码
  1. public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)   
  2.         throws BeansException {   
  3.   
  4.     super(parent);   
  5.     setConfigLocations(configLocations);   
  6.     if (refresh) {   
  7.         refresh();   
  8.     }   
  9. }  
	public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
			throws BeansException {

		super(parent);
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();
		}
	}

 

其中首先设置配置路径 setConfigLocations(configLocations)  ,而后进行刷新 refresh(), 而这个refresh()方法是Ioc容器初始化的入口

2.refresh方法的结构

 refresh方法由AbstractApplicationContext实现

Java代码 复制代码 收藏代码
  1. public void refresh() throws BeansException, IllegalStateException {   
  2.         synchronized (this.startupShutdownMonitor) {   
  3.             // Prepare this context for refreshing.   
  4.             prepareRefresh();   
  5.   
  6.             // Tell the subclass to refresh the internal bean factory.   
  7.             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();   
  8.   
  9.             // Prepare the bean factory for use in this context.   
  10.             prepareBeanFactory(beanFactory);   
  11.   
  12.             try {   
  13.                 // Allows post-processing of the bean factory in context subclasses.   
  14.                 postProcessBeanFactory(beanFactory);   
  15.   
  16.                 // Invoke factory processors registered as beans in the context.   
  17.                 invokeBeanFactoryPostProcessors(beanFactory);   
  18.   
  19.                 // Register bean processors that intercept bean creation.   
  20.                 registerBeanPostProcessors(beanFactory);   
  21.   
  22.                 // Initialize message source for this context.   
  23.                 initMessageSource();   
  24.   
  25.                 // Initialize event multicaster for this context.   
  26.                 initApplicationEventMulticaster();   
  27.   
  28.                 // Initialize other special beans in specific context subclasses.   
  29.                 onRefresh();   
  30.   
  31.                 // Check for listener beans and register them.   
  32.                 registerListeners();   
  33.   
  34.                 // Instantiate all remaining (non-lazy-init) singletons.   
  35.                 finishBeanFactoryInitialization(beanFactory);   
  36.   
  37.                 // Last step: publish corresponding event.   
  38.                 finishRefresh();   
  39.             }   
  40.   
  41.             catch (BeansException ex) {   
  42.                 // Destroy already created singletons to avoid dangling resources.   
  43.                 destroyBeans();   
  44.   
  45.                 // Reset 'active' flag.   
  46.                 cancelRefresh(ex);   
  47.   
  48.                 // Propagate exception to caller.   
  49.                 throw ex;   
  50.             }   
  51.         }   
  52.     }  
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) {
				// 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()方法

 

3.启动对BeanDefination的载入

还是在ApplicationContext类中

Java代码 复制代码 收藏代码
  1. protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {   
  2.     refreshBeanFactory();   
  3.     ConfigurableListableBeanFactory beanFactory = getBeanFactory();   
  4.     if (logger.isDebugEnabled()) {   
  5.         logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);   
  6.     }   
  7.     return beanFactory;   
  8. }  
	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}

 它的第一步交给一个抽象方法refreshBeanFactory(), 具体的实现在AbstractRefreshableApplicationContext类中

 

Java代码 复制代码 收藏代码
  1. @Override  
  2. protected final void refreshBeanFactory() throws BeansException {   
  3.     if (hasBeanFactory()) {   
  4.         destroyBeans();   
  5.         closeBeanFactory();   
  6.     }   
  7.     try {   
  8.         DefaultListableBeanFactory beanFactory = createBeanFactory();   
  9.         beanFactory.setSerializationId(getId());   
  10.         customizeBeanFactory(beanFactory);   
  11.         loadBeanDefinitions(beanFactory);   
  12.         synchronized (this.beanFactoryMonitor) {   
  13.             this.beanFactory = beanFactory;   
  14.         }   
  15.     }   
  16.     catch (IOException ex) {   
  17.         throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);   
  18.     }   
  19. }  
	@Override
	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容器

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

 

4.BeanFactory将载入工作交给BeanDefinationReader

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

Java代码 复制代码 收藏代码
  1. @Override  
  2. protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {   
  3.     // Create a new XmlBeanDefinitionReader for the given BeanFactory.   
  4.     XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);   
  5.   
  6.     // Configure the bean definition reader with this context's   
  7.     // resource loading environment.   
  8.     beanDefinitionReader.setResourceLoader(this);   
  9.     beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));   
  10.   
  11.     // Allow a subclass to provide custom initialization of the reader,   
  12.     // then proceed with actually loading the bean definitions.   
  13.     initBeanDefinitionReader(beanDefinitionReader);   
  14.     loadBeanDefinitions(beanDefinitionReader);   
  15. }  
	@Override
	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.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配置,接下来重载到loadBeanDefinitions(beanDefinitionReader);

Java代码 复制代码 收藏代码
  1. protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {   
  2.     Resource[] configResources = getConfigResources();   
  3.     if (configResources != null) {   
  4.         reader.loadBeanDefinitions(configResources);   
  5.     }   
  6.     String[] configLocations = getConfigLocations();   
  7.     if (configLocations != null) {   
  8.         reader.loadBeanDefinitions(configLocations);   
  9.     }   
  10. }  
	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方法

Java代码 复制代码 收藏代码
  1. public int loadBeanDefinitions(Resource[] resources) throws BeanDefinitionStoreException {   
  2.     Assert.notNull(resources, "Resource array must not be null");   
  3.     int counter = 0;   
  4.     for (Resource resource : resources) {   
  5.         counter += loadBeanDefinitions(resource);   
  6.     }   
  7.     return counter;   
  8. }  
	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 中

Java代码 复制代码 收藏代码
  1. public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {   
  2.     return loadBeanDefinitions(new EncodedResource(resource));   
  3. }  
	public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(new EncodedResource(resource));
	}

重载到

Java代码 复制代码 收藏代码
  1. public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {   
  2.         Assert.notNull(encodedResource, "EncodedResource must not be null");   
  3.         if (logger.isInfoEnabled()) {   
  4.             logger.info("Loading XML bean definitions from " + encodedResource.getResource());   
  5.         }   
  6.   
  7.         Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();   
  8.         if (currentResources == null) {   
  9.             currentResources = new HashSet<EncodedResource>(4);   
  10.             this.resourcesCurrentlyBeingLoaded.set(currentResources);   
  11.         }   
  12.         if (!currentResources.add(encodedResource)) {   
  13.             throw new BeanDefinitionStoreException(   
  14.                     "Detected recursive loading of " + encodedResource + " - check your import definitions!");   
  15.         }   
  16.         try {   
  17.             InputStream inputStream = encodedResource.getResource().getInputStream();   
  18.             try {   
  19.                 InputSource inputSource = new InputSource(inputStream);   
  20.                 if (encodedResource.getEncoding() != null) {   
  21.                     inputSource.setEncoding(encodedResource.getEncoding());   
  22.                 }   
  23.                 return doLoadBeanDefinitions(inputSource, encodedResource.getResource());   
  24.             }   
  25.             finally {   
  26.                 inputStream.close();   
  27.             }   
  28.         }   
  29.         catch (IOException ex) {   
  30.             throw new BeanDefinitionStoreException(   
  31.                     "IOException parsing XML document from " + encodedResource.getResource(), ex);   
  32.         }   
  33.         finally {   
  34.             currentResources.remove(encodedResource);   
  35.             if (currentResources.isEmpty()) {   
  36.                 this.resourcesCurrentlyBeingLoaded.set(null);   
  37.             }   
  38.         }   
  39.     }  
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 recursive 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.set(null);
			}
		}
	}

 

 

在此类中主要是对输入流进行编码操作,然后调用doLoadBeanDefinitions(inputSource, encodedResource.getResource())方法

 

5.XmlBeanDefinitionReader将载入工作交给W3C的dom

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

doLoadBeanDefinitions(inputSource, encodedResource.getResource())方法正式引入dom

Java代码 复制代码 收藏代码
  1. protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)   
  2.             throws BeanDefinitionStoreException {   
  3.         try {   
  4.             int validationMode = getValidationModeForResource(resource);   
  5.             Document doc = this.documentLoader.loadDocument(   
  6.                     inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());   
  7.             return registerBeanDefinitions(doc, resource);   
  8.         }   
  9.         catch (BeanDefinitionStoreException ex) {   
  10.             throw ex;   
  11.         }   
  12.         catch (SAXParseException ex) {   
  13.             throw new XmlBeanDefinitionStoreException(resource.getDescription(),   
  14.                     "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);   
  15.         }   
  16.         catch (SAXException ex) {   
  17.             throw new XmlBeanDefinitionStoreException(resource.getDescription(),   
  18.                     "XML document from " + resource + " is invalid", ex);   
  19.         }   
  20.         catch (ParserConfigurationException ex) {   
  21.             throw new BeanDefinitionStoreException(resource.getDescription(),   
  22.                     "Parser configuration exception parsing XML from " + resource, ex);   
  23.         }   
  24.         catch (IOException ex) {   
  25.             throw new BeanDefinitionStoreException(resource.getDescription(),   
  26.                     "IOException parsing XML document from " + resource, ex);   
  27.         }   
  28.         catch (Throwable ex) {   
  29.             throw new BeanDefinitionStoreException(resource.getDescription(),   
  30.                     "Unexpected exception parsing XML document from " + resource, ex);   
  31.         }   
  32.     }  
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)方法

Java代码 复制代码 收藏代码
  1. public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {   
  2.     // Read document based on new BeanDefinitionDocumentReader SPI.   
  3.     BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();   
  4.     int countBefore = getRegistry().getBeanDefinitionCount();   
  5.     documentReader.registerBeanDefinitions(doc, createReaderContext(resource));   
  6.     return getRegistry().getBeanDefinitionCount() - countBefore;   
  7. }  
	public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		// Read document based on new BeanDefinitionDocumentReader SPI.
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		int countBefore = getRegistry().getBeanDefinitionCount();
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

 

此方法统计了注册的BeanDefinition的个数,返回一个int值,而具体的注册工作在BeanDefinitionDocumentReader 接口的实现类DefaultBeanDefinitionDocumentReader 中registerBeanDefinitions(doc, createReaderContext(resource))方法实现

 

6.BeanDefinitionDocumentReader将载入工作交给代理类BeanDefinationParserDelegate

DefaultBeanDefinitionDocumentReader的registerBeanDefinitions(doc, createReaderContext(resource))方法

Java代码 复制代码 收藏代码
  1. public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {   
  2.     this.readerContext = readerContext;   
  3.   
  4.     logger.debug("Loading bean definitions");   
  5.     Element root = doc.getDocumentElement();   
  6.   
  7.     BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);   
  8.   
  9.     preProcessXml(root);   
  10.     parseBeanDefinitions(root, delegate);   
  11.     postProcessXml(root);   
  12. }  
	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;

		logger.debug("Loading bean definitions");
		Element root = doc.getDocumentElement();

		BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);

		preProcessXml(root);
		parseBeanDefinitions(root, delegate);
		postProcessXml(root);
	}

 

其中首先得到dom结构的根,然后由根进行分析

然后引入BeanDefinitionParserDelegate 代理类对dom结构进行分析,调用parseBeanDefinitions(root, delegate)方法

Java代码 复制代码 收藏代码
  1. protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {   
  2.     if (delegate.isDefaultNamespace(delegate.getNamespaceURI(root))) {   
  3.         NodeList nl = root.getChildNodes();   
  4.         for (int i = 0; i < nl.getLength(); i++) {   
  5.             Node node = nl.item(i);   
  6.             if (node instanceof Element) {   
  7.                 Element ele = (Element) node;   
  8.                 String namespaceUri = delegate.getNamespaceURI(ele);   
  9.                 if (delegate.isDefaultNamespace(namespaceUri)) {   
  10.                     parseDefaultElement(ele, delegate);   
  11.                 }   
  12.                 else {   
  13.                     delegate.parseCustomElement(ele);   
  14.                 }   
  15.             }   
  16.         }   
  17.     }   
  18.     else {   
  19.         delegate.parseCustomElement(root);   
  20.     }   
  21. }  
	protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		if (delegate.isDefaultNamespace(delegate.getNamespaceURI(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;
					String namespaceUri = delegate.getNamespaceURI(ele);
					if (delegate.isDefaultNamespace(namespaceUri)) {
						parseDefaultElement(ele, delegate);
					}
					else {
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}

 其中最主要的操作是在调用parseDefaultElement(ele, delegate)方法中进行

Java代码 复制代码 收藏代码
  1. private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {   
  2.     if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {   
  3.         importBeanDefinitionResource(ele);   
  4.     }   
  5.     else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {   
  6.         processAliasRegistration(ele);   
  7.     }   
  8.     else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {   
  9.         processBeanDefinition(ele, delegate);   
  10.     }   
  11. }  
	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);
		}
	}

 

从这个方法里面我们就能看出来底层元素的端倪了,首先判断Node是否为import节点,然后是alias节点,最后是bean节点,我们关心的是bean节点,processBeanDefinition(ele, delegate)方法

Java代码 复制代码 收藏代码
  1. protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {   
  2.     BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);   
  3.     if (bdHolder != null) {   
  4.         bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);   
  5.         try {   
  6.             // Register the final decorated instance.   
  7.             BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());   
  8.         }   
  9.         catch (BeanDefinitionStoreException ex) {   
  10.             getReaderContext().error("Failed to register bean definition with name '" +   
  11.                     bdHolder.getBeanName() + "'", ele, ex);   
  12.         }   
  13.         // Send registration event.   
  14.         getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));   
  15.     }   
  16. }  
	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 生成BeanDefination的包装类BeanDefinitionHolder ,然后再进行一些修饰工作,这里把工作正式交给BeanDefinitionParserDelegate

 

7.BeanDefinitionParserDelegate 中的解析工作

BeanDefinition的解析主要在BeanDefinitionParserDelegate 的parseBeanDefinitionElement(ele)方法中进行,重载到

Java代码 复制代码 收藏代码
  1. public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {   
  2.     String id = ele.getAttribute(ID_ATTRIBUTE);   
  3.     String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);   
  4.   
  5.     List<String> aliases = new ArrayList<String>();   
  6.     if (StringUtils.hasLength(nameAttr)) {   
  7.         String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BEAN_NAME_DELIMITERS);   
  8.         aliases.addAll(Arrays.asList(nameArr));   
  9.     }   
  10.   
  11.     String beanName = id;   
  12.     if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {   
  13.         beanName = aliases.remove(0);   
  14.         if (logger.isDebugEnabled()) {   
  15.             logger.debug("No XML 'id' specified - using '" + beanName +   
  16.                     "' as bean name and " + aliases + " as aliases");   
  17.         }   
  18.     }   
  19.   
  20.     if (containingBean == null) {   
  21.         checkNameUniqueness(beanName, aliases, ele);   
  22.     }   
  23.   
  24.     AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);   
  25.     if (beanDefinition != null) {   
  26.         if (!StringUtils.hasText(beanName)) {   
  27.             try {   
  28.                 if (containingBean != null) {   
  29.                     beanName = BeanDefinitionReaderUtils.generateBeanName(   
  30.                             beanDefinition, this.readerContext.getRegistry(), true);   
  31.                 }   
  32.                 else {   
  33.                     beanName = this.readerContext.generateBeanName(beanDefinition);   
  34.                     // Register an alias for the plain bean class name, if still possible,   
  35.                     // if the generator returned the class name plus a suffix.   
  36.                     // This is expected for Spring 1.2/2.0 backwards compatibility.   
  37.                     String beanClassName = beanDefinition.getBeanClassName();   
  38.                     if (beanClassName != null &&   
  39.                             beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&   
  40.                             !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {   
  41.                         aliases.add(beanClassName);   
  42.                     }   
  43.                 }   
  44.                 if (logger.isDebugEnabled()) {   
  45.                     logger.debug("Neither XML 'id' nor 'name' specified - " +   
  46.                             "using generated bean name [" + beanName + "]");   
  47.                 }   
  48.             }   
  49.             catch (Exception ex) {   
  50.                 error(ex.getMessage(), ele);   
  51.                 return null;   
  52.             }   
  53.         }   
  54.         String[] aliasesArray = StringUtils.toStringArray(aliases);   
  55.         return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);   
  56.     }   
  57.   
  58.     return null;   
  59. }  
	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, BEAN_NAME_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(ele, beanName, containingBean)方法

Java代码 复制代码 收藏代码
  1. public AbstractBeanDefinition parseBeanDefinitionElement(   
  2.         Element ele, String beanName, BeanDefinition containingBean) {   
  3.   
  4.     this.parseState.push(new BeanEntry(beanName));   
  5.   
  6.     String className = null;   
  7.     if (ele.hasAttribute(CLASS_ATTRIBUTE)) {   
  8.         className = ele.getAttribute(CLASS_ATTRIBUTE).trim();   
  9.     }   
  10.   
  11.     try {   
  12.         String parent = null;   
  13.         if (ele.hasAttribute(PARENT_ATTRIBUTE)) {   
  14.             parent = ele.getAttribute(PARENT_ATTRIBUTE);   
  15.         }   
  16.         AbstractBeanDefinition bd = createBeanDefinition(className, parent);   
  17.   
  18.         parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);   
  19.         bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));   
  20.   
  21.         parseMetaElements(ele, bd);   
  22.         parseLookupOverrideSubElements(ele, bd.getMethodOverrides());   
  23.         parseReplacedMethodSubElements(ele, bd.getMethodOverrides());   
  24.   
  25.         parseConstructorArgElements(ele, bd);   
  26.         parsePropertyElements(ele, bd);   
  27.         parseQualifierElements(ele, bd);   
  28.   
  29.         bd.setResource(this.readerContext.getResource());   
  30.         bd.setSource(extractSource(ele));   
  31.   
  32.         return bd;   
  33.     }   
  34.     catch (ClassNotFoundException ex) {   
  35.         error("Bean class [" + className + "] not found", ele, ex);   
  36.     }   
  37.     catch (NoClassDefFoundError err) {   
  38.         error("Class that bean class [" + className + "] depends on not found", ele, err);   
  39.     }   
  40.     catch (Throwable ex) {   
  41.         error("Unexpected failure during bean definition parsing", ele, ex);   
  42.     }   
  43.     finally {   
  44.         this.parseState.pop();   
  45.     }   
  46.   
  47.     return null;   
  48. }  
	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节点,replaced-method节点,构造函数设置节点,最后是比较复杂的property节点,我们继续分析比较复杂的property节点的解析,parsePropertyElements(ele, bd)方法

Java代码 复制代码 收藏代码
  1. public void parsePropertyElements(Element beanEle, BeanDefinition bd) {   
  2.     NodeList nl = beanEle.getChildNodes();   
  3.     for (int i = 0; i < nl.getLength(); i++) {   
  4.         Node node = nl.item(i);   
  5.         if (node instanceof Element && nodeNameEquals(node, PROPERTY_ELEMENT)) {   
  6.             parsePropertyElement((Element) node, bd);   
  7.         }   
  8.     }   
  9. }  
	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 (node instanceof Element && nodeNameEquals(node, PROPERTY_ELEMENT)) {
				parsePropertyElement((Element) node, bd);
			}
		}
	}

 将bean节点的子元素逐个取出判断是否为property节点,然后进行解析,parsePropertyElement((Element) node, bd)方法

Java代码 复制代码 收藏代码
  1. public void parsePropertyElement(Element ele, BeanDefinition bd) {   
  2.     String propertyName = ele.getAttribute(NAME_ATTRIBUTE);   
  3.     if (!StringUtils.hasLength(propertyName)) {   
  4.         error("Tag 'property' must have a 'name' attribute", ele);   
  5.         return;   
  6.     }   
  7.     this.parseState.push(new PropertyEntry(propertyName));   
  8.     try {   
  9.         if (bd.getPropertyValues().contains(propertyName)) {   
  10.             error("Multiple 'property' definitions for property '" + propertyName + "'", ele);   
  11.             return;   
  12.         }   
  13.         Object val = parsePropertyValue(ele, bd, propertyName);   
  14.         PropertyValue pv = new PropertyValue(propertyName, val);   
  15.         parseMetaElements(ele, pv);   
  16.         pv.setSource(extractSource(ele));   
  17.         bd.getPropertyValues().addPropertyValue(pv);   
  18.     }   
  19.     finally {   
  20.         this.parseState.pop();   
  21.     }   
  22. }  
	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(ele, bd, propertyName)方法

Java代码 复制代码 收藏代码
  1. public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {   
  2.     String elementName = (propertyName != null) ?   
  3.                     "<property> element for property '" + propertyName + "'" :   
  4.                     "<constructor-arg> element";   
  5.   
  6.     // Should only have one child element: ref, value, list, etc.   
  7.     NodeList nl = ele.getChildNodes();   
  8.     Element subElement = null;   
  9.     for (int i = 0; i < nl.getLength(); i++) {   
  10.         Node node = nl.item(i);   
  11.         if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&   
  12.                 !nodeNameEquals(node, META_ELEMENT)) {   
  13.             // Child element is what we're looking for.   
  14.             if (subElement != null) {   
  15.                 error(elementName + " must not contain more than one sub-element", ele);   
  16.             }   
  17.             else {   
  18.                 subElement = (Element) node;   
  19.             }   
  20.         }   
  21.     }   
  22.   
  23.     boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);   
  24.     boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);   
  25.     if ((hasRefAttribute && hasValueAttribute) ||   
  26.             ((hasRefAttribute || hasValueAttribute) && subElement != null)) {   
  27.         error(elementName +   
  28.                 " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);   
  29.     }   
  30.   
  31.     if (hasRefAttribute) {   
  32.         String refName = ele.getAttribute(REF_ATTRIBUTE);   
  33.         if (!StringUtils.hasText(refName)) {   
  34.             error(elementName + " contains empty 'ref' attribute", ele);   
  35.         }   
  36.         RuntimeBeanReference ref = new RuntimeBeanReference(refName);   
  37.         ref.setSource(extractSource(ele));   
  38.         return ref;   
  39.     }   
  40.     else if (hasValueAttribute) {   
  41.         TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));   
  42.         valueHolder.setSource(extractSource(ele));   
  43.         return valueHolder;   
  44.     }   
  45.     else if (subElement != null) {   
  46.         return parsePropertySubElement(subElement, bd);   
  47.     }   
  48.     else {   
  49.         // Neither child element nor "ref" or "value" attribute found.   
  50.         error(elementName + " must specify a ref or value", ele);   
  51.         return null;   
  52.     }   
  53. }  
	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(subElement, bd)方法,重载到

Java代码 复制代码 收藏代码
  1. public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {   
  2.     if (!isDefaultNamespace(getNamespaceURI(ele))) {   
  3.         return parseNestedCustomElement(ele, bd);   
  4.     }   
  5.     else if (nodeNameEquals(ele, BEAN_ELEMENT)) {   
  6.         BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);   
  7.         if (nestedBd != null) {   
  8.             nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);   
  9.         }   
  10.         return nestedBd;   
  11.     }   
  12.     else if (nodeNameEquals(ele, REF_ELEMENT)) {   
  13.         // A generic reference to any name of any bean.   
  14.         String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);   
  15.         boolean toParent = false;   
  16.         if (!StringUtils.hasLength(refName)) {   
  17.             // A reference to the id of another bean in the same XML file.   
  18.             refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);   
  19.             if (!StringUtils.hasLength(refName)) {   
  20.                 // A reference to the id of another bean in a parent context.   
  21.                 refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);   
  22.                 toParent = true;   
  23.                 if (!StringUtils.hasLength(refName)) {   
  24.                     error("'bean', 'local' or 'parent' is required for <ref> element", ele);   
  25.                     return null;   
  26.                 }   
  27.             }   
  28.         }   
  29.         if (!StringUtils.hasText(refName)) {   
  30.             error("<ref> element contains empty target attribute", ele);   
  31.             return null;   
  32.         }   
  33.         RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);   
  34.         ref.setSource(extractSource(ele));   
  35.         return ref;   
  36.     }   
  37.     else if (nodeNameEquals(ele, IDREF_ELEMENT)) {   
  38.         return parseIdRefElement(ele);   
  39.     }   
  40.     else if (nodeNameEquals(ele, VALUE_ELEMENT)) {   
  41.         return parseValueElement(ele, defaultValueType);   
  42.     }   
  43.     else if (nodeNameEquals(ele, NULL_ELEMENT)) {   
  44.         // It's a distinguished null value. Let's wrap it in a TypedStringValue   
  45.         // object in order to preserve the source location.   
  46.         TypedStringValue nullHolder = new TypedStringValue(null);   
  47.         nullHolder.setSource(extractSource(ele));   
  48.         return nullHolder;   
  49.     }   
  50.     else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {   
  51.         return parseArrayElement(ele, bd);   
  52.     }   
  53.     else if (nodeNameEquals(ele, LIST_ELEMENT)) {   
  54.         return parseListElement(ele, bd);   
  55.     }   
  56.     else if (nodeNameEquals(ele, SET_ELEMENT)) {   
  57.         return parseSetElement(ele, bd);   
  58.     }   
  59.     else if (nodeNameEquals(ele, MAP_ELEMENT)) {   
  60.         return parseMapElement(ele, bd);   
  61.     }   
  62.     else if (nodeNameEquals(ele, PROPS_ELEMENT)) {   
  63.         return parsePropsElement(ele);   
  64.     }   
  65.     else {   
  66.         error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);   
  67.         return null;   
  68.     }   
  69. }  
	public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
		if (!isDefaultNamespace(getNamespaceURI(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。

 

到这里配置文件的载入基本上已经到底了,如果对以上元素的配置感兴趣的话,可以继续查看源代码。这里只是包含配置文件的载入过程,并不包括在Ioc容器中的注册,以及依赖注入的过程。

 

 

 

 

声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
分享到:
评论

相关推荐

    Spring集成MongoDB官方指定jar包:spring-data-mongodb-1.4.1.RELEASE.jar

    Spring集成MongoDB官方指定jar包:spring-data-mongodb-1.4.1.RELEASE.jar

    项目配置文件( spring-mvc.xml spring-mybatis.xml web.xml log4j.properties)

    1. **spring-mvc.xml**: 这是Spring MVC框架的核心配置文件,用于设置DispatcherServlet的行为,管理控制器(Controller)、视图解析器(View Resolver)、数据绑定器(DataBinder)等组件。例如,它会定义bean,如...

    SSM整合配置文件、spring-mvc.xml、spring-mybatis.xml、spring.xml、config.properties、log4j.p

    config.properties:数据库配置文件 log4j.properties:mybatis日志文件 spring-mvc.xml:spring-MVC配置文件 spring-mybatis.xml:mybatis的配置文件 spring.xml

    spring-mybatis.xml配置文件

    主要用于spring和mybatis的整合,实现SSM架构的应用。

    Spring boot 示例 官方 Demo

    spring-boot-mybaits-xml:xml配置版本 spring-boot-mybatis-mulidatasource:springboot+mybatis多数据源最简解决方案 spring-boot-mybatis-annotation-mulidatasource:springboot+mybatis(注解版)多数据源最简...

    SpringMVC源码总结(二)mvc:mvc:annotation-driven背后的那些事

    首先,`mvc:annotation-driven`是一个XML配置元素,它简化了对Spring MVC应用中注解驱动功能的配置。通过添加这个元素,我们无需手动注册如`HandlerMapping`、`HandlerAdapter`、`ConversionService`、`Validator`等...

    springcloud项目,解决unknown问题

    检查所有依赖是否已经正确导入,包括Spring Cloud的起步依赖(如`spring-cloud-starter-netflix-eureka-client`)和Spring Boot的起步依赖(如`spring-boot-starter-web`)。 2. **Maven仓库问题**:如果Maven无法...

    参照阿里druid整理druid-spring-boot-starter的demo

    1. **依赖添加**:在`pom.xml`文件中引入`druid-spring-boot-starter`依赖,如下: ```xml &lt;groupId&gt;com.alibaba&lt;/groupId&gt; &lt;artifactId&gt;druid-spring-boot-starter 版本号 ``` 2. **配置数据源**:在`...

    spring:spring源码阅读-spring源码阅读

    注意在spring-src-read模块下的build.gradle中添加compile(project(":spring-context")) 。 环境测试 工程目录如下: 新建配置类 @Configuration @ComponentScan ( " com.fchen " ) public class MyConfig { } 新建...

    官方原版源码spring-framework-5.1.8.RELEASE.zip

    9. **XML与Java配置**:Spring支持XML配置和基于Java的配置,后者在5.x版本中逐渐成为首选。这两种配置方式各有优缺点,理解和掌握两者可以帮助开发者灵活选择合适的配置方式。 10. **Spring Expression Language ...

    官方原版源码spring-framework-4.3.23.RELEASE.zip

    接下来是"spring-framework-4.3.23.RELEASE-schema.zip",这个文件包含Spring的XML配置模式,这些模式定义了Spring配置文件的结构和约束。通过分析这些模式,我们可以了解到Spring如何解析和验证配置文件,以及如何...

    spring-aop-3.0.xsd spring-beans-3.0 spring-context-3.0.xsd spring-mvc-3.1.xsd

    `spring-beans-3.0.xsd` 文件定义了 Spring 容器如何读取并解析 XML 配置文件,来实例化、装配和管理 beans。在这个文件中,你可以定义 bean 的 id、class、属性、依赖注入等。通过版本号 3.0,我们可以看出这是针对...

    官方原版源码spring-framework-5.1.4.RELEASE.zip

    `spring-framework-5.1.4.RELEASE-schema.zip`包含了Spring的XML配置schema,这些schema定义了XML配置文件的结构和约束,使得配置更加规范,同时也支持IDE的自动补全功能,提升开发效率。 在5.1.4版本中,Spring对...

    官方原版源码spring-framework-5.1.6.RELEASE.zip

    而`spring-framework-5.1.6.RELEASE-schema.zip`则包含了Spring配置文件的XML Schema定义,帮助我们理解和验证配置的正确性。 7. **模块化设计**:Spring Framework采用模块化设计,每个模块都有明确的职责,这在...

    logback-spring.xml文件配置

    logback-spring.xml文件配置,1、异步日志,2、滚动日志,存放固定时长的日志,超过时间的自动删除,3、单个文件超过指定大小,分成多个,防止单个文件过大,查看不方便

    spring-boot-2.0.0.M7 源码包

    这个源码包,"spring-boot-2.0.0.M7",是Spring Boot的2.0.0预发布版本,M7代表的是第七个Milestone版本,即在正式版发布前的阶段性版本,通常用于测试和完善功能。 Spring Boot的核心特点包括自动配置、起步依赖、...

    spring-framework-2.0-m1-with-dependencies.rar

    4. **XML解析库**:如DOM4J、Xerces,用于解析XML配置文件。 5. **Servlet容器库**:如Tomcat、Jetty,Spring Web模块在此基础上运行。 四、使用指南 1. **环境搭建**:确保JDK、构建工具(如Maven或Gradle)、IDE...

    springmvc-config.xml

    这是一个springmvc-config.xml文件,&lt;?xml version="1.0" encoding="UTF-8"?&gt; xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:...

    spring-boot-2.7.0.zip源码

    《Spring Boot 2.7.0 源码解析与深度探索》 Spring Boot作为Java开发中的一个核心框架,以其便捷的起步配置、自动化配置和一站式的解决方案深受开发者喜爱。当我们深入研究Spring Boot 2.7.0的源码时,可以更深刻地...

    spring源码--AOP流程--笔记.docx

    在这个过程中,Spring AOP 使用 DefaultBeanDefinitionDocumentReader 来解析 XML 文件,并生成 Bean 定义对象。 2. 解析 AOP 配置:在解析 Bean 定义文件时,Spring AOP 也会解析 AOP 配置文件,例如 `&lt;aop:config...

Global site tag (gtag.js) - Google Analytics