1. 程式人生 > >Spring IoC容器的初始化過程

Spring IoC容器的初始化過程

轉載自:http://blog.csdn.net/u010723709/article/details/47046211
原題是:2 IOC容器初始化過程
作者:@小小旭GISer

===================================================================================================================================

IOC容器的初始化分為三個過程實現:

  • 第一個過程是Resource資源定位。這個Resouce指的是BeanDefinition的資源定位。這個過程就是容器找資料的過程,就像水桶裝水需要先找到水一樣。
  • 第二個過程是BeanDefinition的載入過程。這個載入過程是把使用者定義好的Bean表示成Ioc容器內部的資料結構,而這個容器內部的資料結構就是BeanDefition。
  • 第三個過程是向IOC容器註冊這些BeanDefinition的過程,這個過程就是將前面的BeanDefition儲存到HashMap中的過程。

上面提到的過程一般是不包括Bean的依賴注入的實現。在Spring中,Bean的載入和依賴注入是兩個獨立的過程。依賴注入一般發生在應用第一次通過getBean向容器索取Bean的時候。下面的一張圖描述了這三個過程呼叫的主要方法,圖中的四個過程其實描述的是上面的第二個過程和第三個過程:

1 Resource定位

下面來看看主要的三個ApplicationContext的實現類是如何定位資源的,也就是找到我們通常所說“applicationContetx.xml”等配置檔案的。

1.1 ClassPathXmlApplicationContext與FileSystemXmlApplicationContext

這兩個類都是非Web容器時,常用的ApplicationContext類。他們很相似,所有的構造方法都在過載呼叫一段核心的程式碼。這段程式碼雖然很短,但是其中是一個很複雜的執行過程,它完成了IOC容器的初始化。

[java] view plain
copy print?
  1. super(parent);  
  2.         setConfigLocations(configLocations);  
  3.         if (refresh) {  
  4.             refresh();  
  5.         }  
super(parent);
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();
		}

這其中的setConfigLocations方法就是在進行資源定位。這個方法在AbstractRefreshableConfigApplicationContext類中實現。這個方法首先進行了非空了檢驗。這個Assert是Spring框架的一個工具類,這裡面進行了一個非空判斷。然後對這個路徑進行了一些處理。這樣就完成了資源的定位。這個定位其實就是使用者主動把配置檔案的位置告訴Spring框架。 [java] view plain copy print?
  1. if (locations != null) {  
  2.             Assert.noNullElements(locations, "Config locations must not be null");  
  3.             this.configLocations = new String[locations.length];  
  4.             for (int i = 0; i < locations.length; i++) {  
  5.                 this.configLocations[i] = resolvePath(locations[i]).trim();  
  6.             }  
  7.         }  
  8.         else {  
  9.             this.configLocations = null;  
  10.         }  
if (locations != null) {
			Assert.noNullElements(locations, "Config locations must not be null");
			this.configLocations = new String[locations.length];
			for (int i = 0; i < locations.length; i++) {
				this.configLocations[i] = resolvePath(locations[i]).trim();
			}
		}
		else {
			this.configLocations = null;
		}

1.2 XmlWebApplicationContext

這個類是web容器初始化spring IOC容器的類。對於web應用來說,我們通常是不是直接去初始化這個容器的,它的裝載是一個自動進行的過程。這是因為我們在web.xml中配置了這樣一句話,這其實就是spring的入口

[html] view plain copy print?
  1. <listener>
  2.         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  3.     </listener>
<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>


(1)下面來看這個類ContextLoaderListener,從它的定義就能看出,這是一個ServletContextListener,它的核心方法就是下面的contextInitialized事件,也就是當web容器初始化的時候,spring容器也進行了初始化。

[java] view plain copy print?
  1. publicclass ContextLoaderListener extends ContextLoader implements ServletContextListener  
public class ContextLoaderListener extends ContextLoader implements ServletContextListener

[java] view plain copy print?
  1. /** 
  2.  * Initialize the root web application context. 
  3.  */
  4. @Override
  5. publicvoid contextInitialized(ServletContextEvent event) {  
  6.     initWebApplicationContext(event.getServletContext());  
  7. }  
	/**
	 * Initialize the root web application context.
	 */
	@Override
	public void contextInitialized(ServletContextEvent event) {
		initWebApplicationContext(event.getServletContext());
	}
這個方法將servletContext作為引數傳入,它的目標就是為了讀取web.xml配置檔案,找到我們對spring的配置。

(2)下面來看initWebApplicationContext方法,它完成了對webApplictionContext的初始化工作。這個方法裡的有比較重要的幾段程式碼,他們主要完成了webAppliction構建,引數的注入,以及儲存
  • 構建webApplictionContext
[java] view plain copy print?
  1. if (this.context == null) {  
  2.                 this.context = createWebApplicationContext(servletContext);  
  3.             }  
if (this.context == null) {
				this.context = createWebApplicationContext(servletContext);
			}

這段程式碼看字面意思就知道是新建了一個webApplicationContext。它是由一個工具類產生一個新的wac,這個方法中呼叫了determineContextClass方法,它決定了容器初始化為哪種型別的ApplicationContext,因為我們可以在web.xml中對這種型別進行指定。而如果沒有指定的話,就將使用預設的XmlWebApplicationContext。

[java] view plain copy print?
  1. protected Class<?> determineContextClass(ServletContext servletContext) {  
  2.         String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);  
  3.         if (contextClassName != null) {  
  4.             try {  
  5.                 return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());  
  6.             }  
  7.             catch (ClassNotFoundException ex) {  
  8.                 thrownew ApplicationContextException(  
  9.                         "Failed to load custom context class [" + contextClassName + "]", ex);  
  10.             }  
  11.         }  
  12.         else {  
  13.             contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());  
  14.             try {  
  15.                 return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());  
  16.             }  
  17.             catch (ClassNotFoundException ex) {  
  18.                 thrownew ApplicationContextException(  
  19.                         "Failed to load default context class [" + contextClassName + "]", ex);  
  20.             }  
  21.         }  
  22.     }  
protected Class<?> determineContextClass(ServletContext servletContext) {
		String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
		if (contextClassName != null) {
			try {
				return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException(
						"Failed to load custom context class [" + contextClassName + "]", ex);
			}
		}
		else {
			contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
			try {
				return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException(
						"Failed to load default context class [" + contextClassName + "]", ex);
			}
		}
	}
  • 注入引數,初始化這個空的容器 。這個過程的入口是configureAndRefreshWebApplicationContext這個方法中完成了wac的Id設定,將servletContext注入到wac中,還有最重要的方法,就是setConfigLocation.這裡從web.xml中尋找指定的配置檔案的位置,也就是我們通常配置的“contextConfigLocation”屬性
[java] view plain copy print?
  1. String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);  
  2.         if (configLocationParam != null) {  
  3.             wac.setConfigLocation(configLocationParam);  
  4.         }  
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
		if (configLocationParam != null) {
			wac.setConfigLocation(configLocationParam);
		}

那麼如果沒有指定呢?在XMLWebApplicationContext中這樣一些常量,他們表示了配置檔案的預設位置 [java] view plain copy print?
  1. /** Default config location for the root context */
  2.     publicstaticfinal String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";  
  3.     /** Default prefix for building a config location for a namespace */
  4.     publicstaticfinal String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";  
  5.     /** Default suffix for building a config location for a namespace */
  6.     publicstaticfinal String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";  
/** Default config location for the root context */
	public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";

	/** Default prefix for building a config location for a namespace */
	public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";

	/** Default suffix for building a config location for a namespace */
	public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";



  • spring容器初始化完成後,放入serverletContext中,這樣在web容器中就可以拿到applicationContext
[java] view plain copy print?
  1. servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);  
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

2 BeanDefinition載入

這個過程是最繁瑣,也是最重要的一個過程。這一個過程分為以下幾步,

  • 構造一個BeanFactory,也就是IOC容器
  • 呼叫XML解析器得到document物件
  •  按照Spring的規則解析BeanDefition

對於以上過程,都需要一個入口,也就是前面提到的refresh()方法,這個方法AbstractApplicationContext類中,它描述了整個ApplicationContext的初始化過程,比如BeanFactory的更新,MessgaeSource和PostProcessor的註冊等等。它更像是個初始化的提綱,這個過程為Bean的宣告週期管理提供了條件。

[java] view plain copy print?
  1. publicvoid refresh() throws BeansException, IllegalStateException {  
  2.         synchronized (this.startupShutdownMonitor) {  
  3.             // Prepare this context for refreshing.
  4.             prepareRefresh();  
  5.             // Tell the subclass to refresh the internal bean factory.
  6.             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
  7.             // Prepare the bean factory for use in this context.
  8.             prepareBeanFactory(beanFactory);  
  9.             try {  
  10.                 // Allows post-processing of the bean factory in context subclasses.
  11.                 postProcessBeanFactory(beanFactory);  
  12.                 // Invoke factory processors registered as beans in the context.
  13.                 invokeBeanFactoryPostProcessors(beanFactory);  
  14.                 // Register bean processors that intercept bean creation.
  15.                 registerBeanPostProcessors(beanFactory);  
  16.                 // Initialize message source for this context.
  17.                 initMessageSource();  
  18.                 // Initialize event multicaster for this context.
  19.                 initApplicationEventMulticaster();  
  20.                 // Initialize other special beans in specific context subclasses.
  21.                 onRefresh();  
  22.                 // Check for listener beans and register them.
  23.                 registerListeners();  
  24.                 // Instantiate all remaining (non-lazy-init) singletons.
  25.                 finishBeanFactoryInitialization(beanFactory);  
  26.                 // Last step: publish corresponding event.
  27.                 finishRefresh();  
  28.             }  
  29.             catch (BeansException ex) {  
  30.                 logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);  
  31.                 // Destroy already created singletons to avoid dangling resources.
  32.                 destroyBeans();  
  33.                 // Reset 'active' flag.
  34.                 cancelRefresh(ex);  
  35.                 // Propagate exception to caller.
  36.                 throw ex;  
  37.             }  
  38.         }  
  39.     }  
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;
			}
		}
	}

2.1 構建IOC容器

這個過程的入口是refresh方法中的obtainFreshBeanFactory()方法。整個過程構建了一個DefaultListableBeanFactory物件,這也就是IOC容器的實際型別。這一過程的核心如下:

2.1.1 obtainFreshBeanFactory

這個方法的作用是通知子類去初始化ioc容器,它呼叫了AbstractRefreshableApplicationContext的refreshBeanFactory 方法 進行後續工作。同時在日誌是debug模式的時候,向日志輸出初始化結果。

[java] view plain copy print?
  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;
	}

2.1.2 refreshBeanFactory

這個方法在建立IOC容器前,如果已經有容器存在,那麼需要將已有的容器關閉和銷燬,保證refresh之後使用的是新建立的容器。同時 在建立了空的IOC容器後,開始了對BeanDefitions的載入

[java] view plain copy print?
  1. protectedfinalvoid refreshBeanFactory() throws BeansException {  
  2.         if (hasBeanFactory()) {  
  3.             destroyBeans();  
  4.             closeBeanFactory();  
  5.         }  
  6.         try {  
  7.             DefaultListableBeanFactory beanFactory = createBeanFactory();//建立了IOC容器
  8.             beanFactory.setSerializationId(getId());  
  9.             customizeBeanFactory(beanFactory);  
  10.             loadBeanDefinitions(beanFactory);// 啟動對BeanDefitions的載入
  11.             synchronized (this.beanFactoryMonitor) {  
  12.                 this.beanFactory = beanFactory;  
  13.             }  
  14.         }  
  15.         catch (IOException ex) {  
  16.             thrownew ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);  
  17.         }  
  18.     }  
protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();//建立了IOC容器
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);// 啟動對BeanDefitions的載入
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}
[java] view plain copy print?
  1. protected DefaultListableBeanFactory createBeanFactory() {  
  2.         returnnew DefaultListableBeanFactory(getInternalParentBeanFactory());  
  3.     }  
protected DefaultListableBeanFactory createBeanFactory() {
		return new DefaultListableBeanFactory(getInternalParentBeanFactory());
	}

2.2 解析XML檔案

對於Spring,我們通常使用xml形式的配置檔案定義Bean,在對BeanDefition載入之前,首先需要進行的就是XML檔案的解析。整個過程的核心方法如下:


2.2.1 loadBeanDefinitions(DefaultListableBeanFactory beanFactory)

這裡構造一個XmlBeanDefinitionReader物件,把解析工作交給他去實現

[java] view plain copy print?
  1. protectedvoid loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {  
  2.         // 定義一個XmlBeanDefinitionReader物件 用於解析XML
  3.         XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  
  4.         //進行一些初始化和環境配置
  5.         // Configure the bean definition reader with this context's
  6.         // resource loading environment.
  7.         beanDefinitionReader.setEnvironment(this.getEnvironment());  
  8.         beanDefinitionReader.setResourceLoader(this);  
  9.         beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));  
  10.         // Allow a subclass to provide custom initialization of the reader,
  11.         // then proceed with actually loading the bean definitions.
  12.         initBeanDefinitionReader(beanDefinitionReader);  
  13.         //解析入口
  14.         loadBeanDefinitions(beanDefinitionReader);  
  15.     }  
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// 定義一個XmlBeanDefinitionReader物件 用於解析XML
		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);
	}

2.2.2 loadBeanDefinitions

(1) AbstractXmlApplicationContext類 ,利用reader的方法解析,向下呼叫(Load the bean definitions with the given XmlBeanDefinitionReader.)

[java] view plain copy print?
  1. protectedvoid 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);
		}
	}
(2) AbstractBeanDefinitionReader 類 解析Resource  向下呼叫
[java] view plain copy print?
  1. publicint 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;
	}
(3) XmlBeanDefinitionReader 
[java] view plain copy print?
  1. publicint loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {  
  2.         return loadBeanDefinitions(new EncodedResource(resource));  
  3.     }  
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
		return loadBeanDefinitions(new EncodedResource(resource));
	}
在下面方法得到了XML檔案,並開啟IO流,準備進行解析。實際向下呼叫
[java] view plain copy print?
  1. publicint 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.         Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();  
  7.         if (currentResources == null) {  
  8.             currentResources = new HashSet<EncodedResource>(4);  
  9.             this.resourcesCurrentlyBeingLoaded.set(currentResources);  
  10.         }  
  11.         if (!currentResources.add(encodedResource)) {  
  12.             thrownew BeanDefinitionStoreException(  
  13.                     "Detected cyclic loading of " + encodedResource + " - check your import definitions!");  
  14.         }  
  15.         try {  
  16.             InputStream inputStream = encodedResource.getResource().getInputStream();  
  17.             try {  
  18.                 InputSource inputSource = new InputSource(inputStream);  
  19.                 if (encodedResource.getEncoding() != null) {  
  20.                     inputSource.setEncoding(encodedResource.getEncoding());  
  21.                 }  
  22.                 return doLoadBeanDefinitions(inputSource, encodedResource.getResource());  
  23.             }  
  24.             finally {  
  25.                 inputStream.close();  
  26.             }  
  27.         }  
  28.         catch (IOException ex) {  
  29.             thrownew BeanDefinitionStoreException(  
  30.                     "IOException parsing XML document from " + encodedResource.getResource(), ex);  
  31.         }  
  32.         finally {  
  33.             currentResources.remove(encodedResource);  
  34.             if (currentResources.isEmpty()) {  
  35.                 this.resourcesCurrentlyBeingLoaded.remove();  
  36.             }  
  37.         }  
  38.     }  
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();
			}
		}
	}

(4) doLoadBeanDefinitions

下面是它的核心方法,第一句呼叫Spring解析XML的方法得到document物件,而第二句則是載入BeanDefitions的入口

[java] view plain copy print?
  1. try {  
  2.             Document doc = doLoadDocument(inputSource, resource);  
  3.             return registerBeanDefinitions(doc, resource);  
  4.         }  
try {
			Document doc = doLoadDocument(inputSource, resource);
			return registerBeanDefinitions(doc, resource);
		}

2.3 解析Spring資料結構

這一步是將document物件解析成spring內部的bean結構,實際上是AbstractBeanDefinition物件。這個物件的解析結果放入BeanDefinitionHolder中,而整個過程是由BeanDefinitionParserDelegate完成。

2.3.1 registerBeanDefinitions

解析BeanDefinitions的入口,向下呼叫doRegisterBeanDefinitions方法

[java] view plain copy print?
  1. publicvoid registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {  
  2.         this.readerContext = readerContext;  
  3.         logger.debug("Loading bean definitions");  
  4.         Element root = doc.getDocumentElement();  
  5.         doRegisterBeanDefinitions(root);  
  6.     }  
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		logger.debug("Loading bean definitions");
		Element root = doc.getDocumentElement();
		doRegisterBeanDefinitions(root);
	}

2.3.2 doRegisterBeanDefinitions

定義了BeanDefinitionParserDelegate 解析處理器物件,向下呼叫parseBeanDefinitions 方法

[java] view plain copy print?
  1. protectedvoid doRegisterBeanDefinitions(Element root) {  
  2.         // Any nested <beans> elements will cause recursion in this method. In