天天看點

Spring源碼分析----IoC容器(一)

Ioc容器主要包括org.springframework.beans 、org.springframework.context這兩個包。主要的兩個基類就是BeanFactory和ApplicationContext。ApplicationContext擴充了BeanFactory的功能,支援功能更強大,一般我們優先使用。下面我們來說說IoC容器的源碼:

BeanFactory工廠類繼承圖:

Spring源碼分析----IoC容器(一)

說明:從上圖可以看出BeanFactory主要有3個子接口:ListableBeanFactory、HierarchicalBeanFactory 和 AutowireCapableBeanFactory,

他實作了所有的接口。那為何要定義這麼多層次的接口呢?查閱這些接口的源碼和說明發現,每個接口都有他使用的場合,它主要是為了區分在 Spring 内部在操作過程中對象的傳遞和轉化過程中,對對象的資料通路所做的限制。例如 ListableBeanFactory 接口表示這些 Bean 是可清單的,而 HierarchicalBeanFactory 表示的是這些 Bean 是有繼承關系的,也就是每個 Bean 有可能有父 Bean。AutowireCapableBeanFactory 接口定義Bean 的自動裝配規則。這四個接口共同定義了Bean 的集合、Bean 之間的關系、以及 Bean 行為。

他們最終的實作類都是XmlBeanFactory類。也就是說Ioc容器最底層的實作是XmlBeanFactory。下面我們就從XmlBeanFactory來看一下基本的IoC容器的實作過程:

@Deprecated
public class XmlBeanFactory extends DefaultListableBeanFactory {

	private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);


	/**
	 * Create a new XmlBeanFactory with the given resource,
	 * which must be parsable using DOM.
	 * @param resource XML resource to load bean definitions from
	 * @throws BeansException in case of loading or parsing errors
	 */
	public XmlBeanFactory(Resource resource) throws BeansException {
		this(resource, null);
	}

	/**
	 * Create a new XmlBeanFactory with the given input stream,
	 * which must be parsable using DOM.
	 * @param resource XML resource to load bean definitions from
	 * @param parentBeanFactory parent bean factory
	 * @throws BeansException in case of loading or parsing errors
	 */
	public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
		super(parentBeanFactory);
		this.reader.loadBeanDefinitions(resource);
	}
           

XmlBeanFactory類源碼中對類的定義:reads bean definitions from an XML document. Delegates to{@link XmlBeanDefinitionReader} underneath; effectively equivalent to using an XmlBeanDefinitionReader with a DefaultListableBeanFactory. 可以簡單了解為XmlBeanFactory是一個可以讀取xml檔案方式定義的beanDefinition的IoC容器。

從上面源碼中可以看出類中包含了一個XmlBeanDefinitionReader對象reader,根據reader對象去加載beanDefinition,也就是說對xml資訊的處理實際上是由XmlBeanDefinitionReader類來操作的,this.reader.loadBeanDefinitions(resource)有一個參數resource,Resource類是spring為我們處理外部資源(URL資源、File資源資源、ClassPath相關資源等)提供的一個統一接口通路,裡面包括了對資源的打開、讀取、關閉等操作。也就是說reader對象把resource中的xml資源資訊加載到beandefinition中。

說說beandefinition:簡單了解就是一個javabean對象類,用來儲存類如xml檔案配置中的一個個bean資訊。

因實際使用中我們使用ApplicationContext較多,下面我們主要分析下ApplicationContext容器:

看下ApplicationContext類結構圖:

Spring源碼分析----IoC容器(一)

從上圖中可以看出 ApplicationContext 繼承了 BeanFactory,這也說明了 Spring 容器中運作的主體對象是 Bean,另外 ApplicationContext 繼承了 ResourceLoader 接口,使得 ApplicationContext 可以通路到任何外部資源。

ApplicationContext 的子類主要包含兩個方面:

  1. ConfigurableApplicationContext 表示該 Context 是可修改的,也就是在建構 Context 中使用者可以動态添加或修改已有的配置資訊,它下面又有多個子類,其中最經常使用的是可更新的 Context,即 AbstractRefreshableApplicationContext 類。
  2. WebApplicationContext 顧名思義,就是為 web 準備的 Context 他可以直接通路到 ServletContext,通常情況下,這個接口使用的少。

再往下分就是按照建構 Context 的檔案類型,接着就是通路 Context 的方式。這樣一級一級構成了完整的 Context 等級層次。

總體來說 ApplicationContext 必須要完成以下幾件事:

辨別一個應用環境

  • 利用 BeanFactory 建立 Bean 對象
  • 儲存對象關系表
  • 能夠捕獲各種事件

Context 作為 Spring 的 Ioc 容器,基本上整合了 Spring 的大部分功能,或者說是大部分功能的基礎。

AbstractApplicationContext的refresh方法作為IoC運作的主要入口操作方法:

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;
			}
		}
	}
           

bean裝載時序圖:

Spring源碼分析----IoC容器(一)

XmlBeanDefinitionReader類中操作流向:loadBeanDefinition()---->doLoadBeanDefinitions()---->registerBeanDefinitions(doc, resource) 轉到-------》

DefaultBeanDefinitionDocumentReader:doRegisterBeanDefinitions(Element root)----》parseBeanDefinitions()

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);
		}
	}
           

 從上面看 這段就是對xml進行解析的過程,進入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);
		}
	}
           

這段對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));
		}
	}
           

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); 這邊把bean加工好了放到了beandefinition中,下面就是把bean資訊存放到map中。

registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());這裡把xml配置檔案中的一個個bean 以beanName為key beanDefinition對象為值的方式存到DefaultListableBeanFactory類的beanDefinitionMap中。到此bean的裝載過程就結束了。下一篇我們看看bean執行個體化的過程。