Spring IOC過程源碼分析

廢話很少說,咱們先作一個傻瓜版的IOC demo做爲例子

自定義的Bean定義html

class MyBeanDefinition{

    public String id;
    public String className;
    public String value;

    public MyBeanDefinition(String id, String className, String value) {
        this.id = id;
        this.className = className;
        this.value = value;
    }

}
複製代碼

自定義的Bean工廠node

class MyBeanFactory {

    Map<String, Object> beanMap = new HashMap<>();

    public MyBeanFactory(MyBeanDefinition beanDefinition) throws ClassNotFoundException,
            IllegalAccessException, InstantiationException {

        Class<?> beanClass = Class.forName(beanDefinition.className);
        Object bean = beanClass.newInstance();
        ((UserService) bean).setName(beanDefinition.value);
        beanMap.put(beanDefinition.id, bean);

    }

    public Object getBean(String id) {
        return beanMap.get(id);
    }


}

複製代碼

測試傻瓜版IOC容器spring

public class EasyIOC {

    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {

        MyBeanDefinition beanDefinition = new MyBeanDefinition("userService",
                "com.valarchie.UserService", "archie");

        MyBeanFactory beanFactory = new MyBeanFactory(beanDefinition);
        UserService userService = (UserService) beanFactory.getBean("userService");

        System.out.println(userService.getName());

    }


}
複製代碼

看完以上這個傻瓜版的例子咱們能夠思考一下?讓咱們本身實現IOC的容器的關鍵是什麼呢?

按照個人理解,我總結爲如下三步設計模式

  • 讀取xml文件造成DOM對象
  • 讀取DOM文檔對象裏的Bean定義並裝載進BeanFactory中
  • 根據bean定義生成實例放進容器,以供使用

因此,接下來咱們不會通盤分析整個IOC的流程,由於旁枝細節太多讀者看完也雲裏霧裏抓不到重點。
咱們經過分析最重要的這條代碼主幹線來理解IOC的過程。數組

開始分析:

首先咱們從xml的配置方式開始分析,由於Spring最初的配置方式就是利用xml來進行配置,因此大部分人對xml的配置形式較爲熟悉,也比較方便理解。緩存

從ClassPathXmlApplicationContext的構造器開始講起。bash

public class TestSpring {
    public static void main(String[] args) {
        // IOC容器的啓動就從ClassPathXmlApplicationContext的構造方法開始
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");
        UserService userService = (UserService) context.getBean("userService");
        System.out.println(userService.getName());
       
    }
}
複製代碼

進入到構造方法中,調用重載的另外一個構造方法。app

// 建立ClassPathXmlApplicationContext,加載給定的位置的xml文件,並自動刷新context
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
		this(new String[] {configLocation}, true, null);
}
複製代碼

重載的構造方法中,因爲剛纔parrent參數傳爲null,因此不設置父容器。refresh剛纔設置爲true,流程就會進入refresh()方法中dom

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
			throws BeansException {
        // 因爲以前的方法調用將parent設置爲null,因此咱們就不分析了
		super(parent);
		// 設置路徑數組,並依次對配置路徑進行簡單佔位符替換處理,比較簡單,咱們也不進入分析了
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();
		}
}
複製代碼

整個refresh()方法中就是IOC容器啓動的主幹脈絡了,Spring採用了模板方法設計模式進行refresh()方法的設計,先規定好整個IOC容器的具體步驟,而後將每個小步驟由各類不一樣的子類本身實現。ide

全部重要的操做都是圍繞着BeanFactory在進行。
在註釋當中,咱們詳細的列出了每一步方法所完成的事情。ApplicationContext內部持有了FactoryBean的實例。其實ApplicationContext自己最上層的父接口也是BeanFactory,他拓展了BeanFactory以外的功能(提供國際化的消息訪問、資源訪問,如URL和文件、事件傳播、載入多個(有繼承關係)上下文)

咱們先經過閱讀代碼中的註釋來了解大概的脈絡。

public void refresh() throws BeansException, IllegalStateException {
        // 先加鎖防止啓動、結束衝突
		synchronized (this.startupShutdownMonitor) {
			// 在刷新以前作一些準備工做
			// 設置啓動的時間、相關狀態的標誌位(活動、關閉)、初始化佔位符屬性源,並確認
			// 每一個標記爲必須的屬性都是可解析的。
			prepareRefresh();

			// 獲取一個已刷新的BeanFactory實例。
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 定義好Bean工廠的環境特性,例如類加載器,或者後置處理器
			prepareBeanFactory(beanFactory);

			try {
				// 設置在BeanFactory完成初始化以後作一些後置操做,spring留給子類的擴展。
				postProcessBeanFactory(beanFactory);

				// 啓動以前已設置的BeanFactory後置處理器
				invokeBeanFactoryPostProcessors(beanFactory);

				// 註冊Bean處理器
				registerBeanPostProcessors(beanFactory);

				// 爲咱們的應用上下文設置消息源(i18n)
				initMessageSource();

				// 初始化事件廣播器
				initApplicationEventMulticaster();

				// 初始化特殊的Bean在特殊的Context中,默認實現爲空,交給各個具體子類實現
				onRefresh();

				// 檢查監聽器並註冊
				registerListeners();

				// 實例化全部非懶加載的Bean
				finishBeanFactoryInitialization(beanFactory);

				// 最後一步發佈相應的事件
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// 若是啓動失敗的話,要銷燬以前建立的Beans。
				destroyBeans();

				// 重置ApplicationContext內部active的標誌位
				cancelRefresh(ex);

				// 向調用者拋出異常
				throw ex;
			}

			finally {
			    // 重置Spring核心內的緩存,由於咱們可能再也不須要單例bean相關的元數據
				resetCommonCaches();
			}
		}
	}
複製代碼

閱讀完以後咱們重點關注obtainFreshBeanFactory()、finishBeanFactoryInitialization(beanFactory)這兩個方法,由於實質上整個IOC的流程都在這兩個方法當中,其餘的方法一部分是Spring預留給用戶的自定義操做如BeanFactory的後置處理器和Bean後置處理器,一部分是關鍵啓動事件的發佈和監聽操做,一部分是關於AOP的操做。

首先,先從obtainFreshBeanFactory()開始提及。

第一步:讀取xml文件造成DOM對象

在getBeanFactory()方法以前,先調用refreshBeanFactory()方法進行刷新。咱們先說明一下,getBeanFactory()很是簡單,默認實現只是將上一步刷新成功好構建好的Bean工廠進行返回。返回出去的Bean工廠已經加載好Bean定義了。因此在refreshBeanFactory()這個方法中已經包含了第一步讀取xml文件構建DOM對象和第二步解析DOM中的元素生成Bean定義進行保存。記住,這裏僅僅是保存好Bean定義,此時並未涉及Bean的實例化。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
}
複製代碼

進入refreshBeanFactory()方法中

protected final void refreshBeanFactory() throws BeansException {
        // 若是當前ApplicationContext中已存在FactoryBean的話進行銷燬
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
		    // 先生成一個BeanFactory
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			// 設置序列化
			beanFactory.setSerializationId(getId());
			// 設置是否能夠覆蓋Bean定義和是否能夠循環依賴,具體我就不解釋了
			customizeBeanFactory(beanFactory);
			// 加載Bean定義到Factory當中去
			// 重點!
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}
複製代碼

接下來,進入核心方法loadBeanDefinitions(beanFactory)中,參數是剛建立的beanFactory

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// 根據傳入的beanfactory建立一個xml讀取器
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

	
		// 設置bean定義讀取器的相關資源加載環境
		beanDefinitionReader.setEnvironment(this.getEnvironment());
		beanDefinitionReader.setResourceLoader(this);
		beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

		// 這個方法讓子類自定義讀取器Reader的初始化
		initBeanDefinitionReader(beanDefinitionReader);
		// 接着開始實際加載Bean定義
		loadBeanDefinitions(beanDefinitionReader);
	}
複製代碼

進入loadBeanDefinitions(beanDefinitionReader)方法中,參數是剛剛建立好的Reader讀取器。

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        // 若是有已經生成好的Resouce實例的話就直接進行解析。
        // 默認的實現是返回null,由子類自行實現。
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			reader.loadBeanDefinitions(configResources);
		}
		// 沒有Resouces的話就進行路徑解析。
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			reader.loadBeanDefinitions(configLocations);
		}
}

複製代碼

咱們進入reader.loadBeanDefinitions(configLocations)方法中,這裏面方法調用有點繞,我這邊只簡單地描述一下

該方法會根據多個不一樣位置的xml文件依次進行處理。 接着會對路徑的不一樣寫法進行不一樣處理,例如classpath或者WEB-INF的前綴路徑。 根據傳入的locations變量生成對應的Resouces。 緊接着進入reader.loadBeanDefinitions(resource)此時參數是Resource。 在通過一層進入loadBeanDefinitions(new EncodedResource(resource))的方法調用中。

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
	Assert.notNull(encodedResource, "EncodedResource must not be null");
	if (logger.isInfoEnabled()) {
		logger.info("Loading XML bean definitions from " + encodedResource.getResource());
	}
    // 經過ThreadLocal實現的當前currentResource
	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()方法。

// 內部核心代碼就這兩句
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
		
複製代碼

在loadDocument()方法中會生成一個DocumentBuilderImpl對象,這個對象會調用parse方法,在parse方法中使用SAX進行解析剛纔的輸入流包裝的InputSource,生成DOM對象返回。

public Document parse(InputSource is) throws SAXException, IOException {
        if (is == null) {
            throw new IllegalArgumentException(
                DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN,
                "jaxp-null-input-source", null));
        }
        if (fSchemaValidator != null) {
            if (fSchemaValidationManager != null) {
                fSchemaValidationManager.reset();
                fUnparsedEntityHandler.reset();
            }
            resetSchemaValidator();
        }
        // 解析xml
        domParser.parse(is);
        // 獲取剛纔解析好的dom
        Document doc = domParser.getDocument();
        domParser.dropDocumentReferences();
        return doc;
}
複製代碼

此時咱們的xml文件已經加載並解析成DOM結構對象了,第一步已經完成了。

第二步:讀取DOM文檔對象裏的Bean定義並裝載進BeanFactory中

// 內部核心代碼就這兩句
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
		
複製代碼

咱們再回到剛剛講到的這兩句核心代碼,第一句獲取DOM對象後,緊接着第二句registerBeanDefinitions(doc, resource)開始了bean定義的註冊工做。

進入registerBeanDefinitions(doc, resource)方法中

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        // 生成DOM讀取器,這個和剛纔的讀取器不同,以前的讀取器是xml讀取器。
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		// 獲取以前的bean定義數量 
		int countBefore = getRegistry().getBeanDefinitionCount();
		
		// 進入重點
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		
		// 用剛剛又建立的bean定義數量 - 以前的bean定義數量 = 剛剛一共建立的bean定義 
		return getRegistry().getBeanDefinitionCount() - countBefore;
}

複製代碼

進入documentReader.registerBeanDefinitions(doc, createReaderContext(resource))方法。 方法內讀取文檔的root元素。

protected void doRegisterBeanDefinitions(Element root) {
		// Any nested <beans> elements will cause recursion in this method. In
		// order to propagate and preserve <beans> default-* attributes correctly,
		// keep track of the current (parent) delegate, which may be null. Create
		// the new (child) delegate with a reference to the parent for fallback purposes,
		// then ultimately reset this.delegate back to its original (parent) reference.
		// this behavior emulates a stack of delegates without actually necessitating one.
		BeanDefinitionParserDelegate parent = this.delegate;
		
		// 生成Bean定義解析類
		this.delegate = createDelegate(getReaderContext(), root, parent);

        // 若是是xml文檔中的namespace,進行相應處理
		if (this.delegate.isDefaultNamespace(root)) {
			String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
			if (StringUtils.hasText(profileSpec)) {
				String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
						profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
				if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
					if (logger.isInfoEnabled()) {
						logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
								"] not matching: " + getReaderContext().getResource());
					}
					return;
				}
			}
		}

        // spring預留給子類的拓展性方法
		preProcessXml(root);
		
		// 重點
		// 開始解析Bean定義
		parseBeanDefinitions(root, this.delegate);
		
	  // spring預留給子類的拓展性方法
		postProcessXml(root);

		this.delegate = parent;
		
}
複製代碼

進入parseBeanDefinitions(root, this.delegate)。將以前的文檔對象和bean定義解析類做爲參數傳入。

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 {
		    // 非默認命名空間的,進行自定義解析,命名空間就是xml文檔頭內的xmlns,用來定義標籤。
			delegate.parseCustomElement(root);
		}
}
複製代碼

進入到parseDefaultElement(ele, delegate)當中,會發現其實對四種標籤進行分別的解析。

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)) {
		    // 分析Bean標籤
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
}
複製代碼

咱們主要分析Bean元素標籤的解析,進入processBeanDefinition(ele, delegate)方法中最內層。

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
        // 獲取bean標籤內的id
		String id = ele.getAttribute(ID_ATTRIBUTE);
		// 獲取bean標籤內的name
		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));
		}

        // 當沒有設置id的時候
		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");
			}
		}

        // 檢查beanName是否惟一
		if (containingBean == null) {
			checkNameUniqueness(beanName, aliases, ele);
		}
        // 內部作了Bean標籤的解析工做
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
			if (!StringUtils.hasText(beanName)) {
				try {
					if (containingBean != null) {
						beanName = BeanDefinitionReaderUtils.generateBeanName(
								beanDefinition, this.readerContext.getRegistry(), true);
					}
					else {
						beanName = this.readerContext.generateBeanName(beanDefinition);
						// Register an alias for the plain bean class name, if still possible,
						// if the generator returned the class name plus a suffix.
						// This is expected for Spring 1.2/2.0 backwards compatibility.
						String beanClassName = beanDefinition.getBeanClassName();
						if (beanClassName != null &&
								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;
}
複製代碼

將解析好的Bean定義並附加別名數組填入new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray)中進行返回。而後調用如下這個方法。

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry())
複製代碼

最主要的操做就是將剛纔解析好的Bean定義放入beanDefinitionMap中去。

解析成功後將Bean定義進行保存。第二步也已經完成。

第三步:使用建立好的Bean定義,開始實例化Bean。

咱們回到最開始的refresh方法中,在finishBeanFactoryInitialization(beanFactory)方法中,開始實例化非懶加載的Bean對象。咱們跟着調用鏈進入到preInstantiateSingletons()方法中

@Override
public void preInstantiateSingletons() throws BeansException {
	if (this.logger.isDebugEnabled()) {
		this.logger.debug("Pre-instantiating singletons in " + this);
	}

	// 將以前作好的bean定義名列表拷貝放進beanNames中,而後開始遍歷
	List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

	// 觸發全部非懶加載的單例Bean實例化
	for (String beanName : beanNames) {
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		
		// 若是非抽象而且是單例和非懶加載的話
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
		    // 檢測是不是工廠方法Bean。 建立Bean的不一樣方式,讀者可自行百度。
			if (isFactoryBean(beanName)) {
				final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
				boolean isEagerInit;
				if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
					isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
						@Override
						public Boolean run() {
							return ((SmartFactoryBean<?>) factory).isEagerInit();
						}
					}, getAccessControlContext());
				}
				else {
					isEagerInit = (factory instanceof SmartFactoryBean &&
							((SmartFactoryBean<?>) factory).isEagerInit());
				}
				if (isEagerInit) {
					getBean(beanName);
				}
			}
			else {
				getBean(beanName);
			}
		}
	}

    // 關於實例化以後作的自定義操做代碼省略....
}
複製代碼

在該方法中根據Bean實例是經過工廠方法實例仍是普通實例化,最主要的方法仍是getBean(beanName)方法。咱們繼續分析普通實例化的過程。進入getBean()方法當中doGetBean()方法,發現方法參數doGetBean(name, null, null, false)後三個參數所有爲null,它就是整個IOC中的核心代碼。

代碼中先經過實例化Bean,實例化好以後再判斷該Bean所需的依賴,並遞歸調用進行實例化bean,成功後整個IOC的核心流程也就完成了。

protected <T> T doGetBean(
		final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
		throws BeansException {

	final String beanName = transformedBeanName(name);
	Object bean;

	// Eagerly check singleton cache for manually registered singletons.
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		if (logger.isDebugEnabled()) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
						"' that is not fully initialized yet - a consequence of a circular reference");
			}
			else {
				logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
			}
		}
		bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
	}

	else {
		// 若是當前Bean正在建立中的話就直接失敗,
		// 能夠陷入了循環引用。
		if (isPrototypeCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}

		// 檢測Bean定義是否出如今父Bean工廠
		BeanFactory parentBeanFactory = getParentBeanFactory();
		if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
			// 父工廠不爲null而且當前不包含這個Bean定義時
			// 從父工廠去返回Bean
			String nameToLookup = originalBeanName(name);
			if (args != null) {
				// Delegation to parent with explicit args.
				return (T) parentBeanFactory.getBean(nameToLookup, args);
			}
			else {
				// No args -> delegate to standard getBean method.
				return parentBeanFactory.getBean(nameToLookup, requiredType);
			}
		}

        	// 若是不須要類型檢查的話 標記爲已建立
		if (!typeCheckOnly) {
			markBeanAsCreated(beanName);
		}

		try {
		    // 將子Bean定義與父Bean定義進行整合
			final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			// 整合後若是發現是抽象類不能實例 拋出異常
			checkMergedBeanDefinition(mbd, beanName, args);

			// 獲取Bean定義所需的依賴並逐一初始化填充
			String[] dependsOn = mbd.getDependsOn();
			if (dependsOn != null) {
				for (String dep : dependsOn) {
				    // 判斷是否循環依賴
					if (isDependent(beanName, dep)) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
					}
					// 註冊依賴的Bean
					registerDependentBean(dep, beanName);
					try {
					// 遞歸調用生成所需依賴的Bean
						getBean(dep);
					}
					catch (NoSuchBeanDefinitionException ex) {
						throw new BeanCreationException(mbd.getResourceDescription(), beanName,
								"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
					}
				}
			}

			// 若是是單例的話
			if (mbd.isSingleton()) {
				sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
					@Override
					public Object getObject() throws BeansException {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					}
				});
				bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}

            // 若是是原型的話
			else if (mbd.isPrototype()) {
				// It's a prototype -> create a new instance. Object prototypeInstance = null; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } // 非單例和原型 範圍的狀況 else { String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { beforePrototypeCreation(beanName); try { return createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } } }); bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton", ex); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } // 檢測實例Bean的類型和所需類型是否一致 if (requiredType != null && bean != null && !requiredType.isInstance(bean)) { try { return getTypeConverter().convertIfNecessary(bean, requiredType); } catch (TypeMismatchException ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'", ex); } throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); } } return (T) bean; } 複製代碼

根據Bean定義去實例化Bean。第三步也已經完成。

文章篇幅有限,IOC整個的建立過程仍是比較冗長的,但願讀者看完文章對IOC的建立過程有一個主幹脈絡的思路以後仍是須要翻開源碼進行解讀,其實閱讀源碼並不難,由於Spring的代碼註釋都挺健全,若是遇到不清楚的稍微google一下就知道了。建議讀者本身試着一步一步的分析IOC過程的源碼。

轉自個人我的博客 vc2x.com

相關文章
相關標籤/搜索