springIOC源碼深度解析

之前沒有意識到閱讀優秀框架源碼的重要性,直到我閱讀完mybatis、spring IOC、AOP, springMVC的源碼,從中學了很多底層的知識,好比java的反射內省,jdk動態代理,cglib動態代理,體會到源碼中使用了各類設計模式,使得框架具備很是強大的擴展性,那個時候我才發現框架也是很美的。廢話很少說,下面開始咱們的SpringIOC源碼之旅。java

本文采用的源碼版本是5.2.x。爲了咱們更好地理解springIOC,咱們使用的是xml的方式,實際開發中大部分都是是用註解的方式,經驗告訴我,從理解源碼的角度上來說,xml配置是最好不過了。node

閱讀源碼的建議:去spring官網下載最新的源碼,對照着看,否則根本看不下去,以前我就吃過虧,自覺得看書就能把源碼弄明白,當時真是太天真了,看了幾頁就放棄了,由於根本就看不懂。spring

本文假定讀者已經有spring相關的使用基礎,好比如何創建工程,引入spring相關的依賴,並會使用單元測試。bootstrap

引言

閱讀源碼最大的難點就是入口難找,經驗告訴咱們,咱們平時使用到的源碼方式就是閱讀的入口,這和咱們平時開發都是息息相關的。設計模式

建一個maven工程,添加相關依賴,使用單元測試來測試獲取bean的流程。緩存

下面咱們來看看咱們平時都是怎麼使用的springIOC:bash

下面是咱們平時獲取一個bean的原始方式:session

public class TestSpring {
    @Test
    public void testSpring() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");
        Student student = (Student) ctx.getBean("student");
        System.out.println(student);
    }
}
複製代碼

在resource文件夾下新建一個application.xml文件,一般叫 application.xml 或 application-xxx.xml 就能夠了,並配置以下:mybatis

<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
    <bean id="student" class="com.sjc.spring.po.Student">
        <!-- String類型 -->
        <property name="name" value="jiangcong"></property>
        <!-- Integer類型 -->
        <property name="age" value="18"></property>
        <!-- 引用類型 -->
        <property name="course" ref="course"></property>
    </bean>

    <!-- 該類有一個初始化方法 -->
    <bean id="course" class="com.sjc.spring.po.Course"
          init-method="init">
        <!-- String類型 -->
        <property name="name" value="spring"></property>
    </bean>
</beans>

複製代碼

Student類app

public class Student {

	private String name;
	private Integer age;

	private Course course;
  //... 省略getter/setter方法
}
複製代碼

Course類

public class Course {

	private String name;
	//... 省略getter/setter方法
}
複製代碼

例子很簡單,可是也夠引出本文的主題了,探索spring容器如何加裝配置文件,以及如何爲咱們實例化bean,使得咱們經過getBean("student")就能夠獲取到一個Student類的實例,從而理解spring中核心的IOC、DI。

開始閱讀源碼以前,先介紹一下Spring重要的接口,這裏不要求你們掌握,只是到時候進入源碼閱讀部分時候,腦子裏有個印象,再來查找這部分的知識就行了。

Spring重要接口介紹

BeanFactory繼承體系

BeanFactory繼承體系類型圖

看到這些錯綜複雜的類關係圖,咱們不由感慨,spring的龐大。那麼spring爲啥要定義這麼多接口呢?由於每一個接口都有它使用的場合,各個接口之間具備必定的職責,可是又互不干擾,這就是設計模式中的接口隔離原則。你就想一下,若是把這些功能全都在一兩個接口實現,那且不是亂成一團糟。

下面介紹主要類的主要功能:

BeanFactory:

接口主要定義了IOC容器的基本行爲,好比根據各類條件獲取Bean。這裏使用了工廠模式。

ListableBeanFactory:

從名字能夠看出來,這個接口的特色就是能夠生產實例列表,好比根據類型獲取Bean實例獲取的是列表Bean實例

HierarchicalBeanFactory:

主要是實現了Bean工廠的分層。

AutowireCapableBeanFactory:

自動裝配的Bean工廠

這個工廠接口繼承自BeanFacotory,它擴展了自動裝配的功能,根據類定義BeanDefinition裝配 Bean、執行前、後處理器等。

ConfigurableBeanFactory

複雜的配置Bean工廠

ConfigurableListableBeanFactory

這個類很是之龐大,這個工廠接口總共有83個接口,包含了BeanFactory體系目前的全部方法。

BeanDefinitionRegistry

用來操做定義在工廠內部的BeanDefinition對象。好比註冊BeanDefinition獲取BeanDefinition

BeanDefinition繼承體系

ApplicationContext繼承體系

源碼解析篇

建立IOC容器

介紹完了主要的接口,咱們進入源碼分析

分析入口是: AbstractApplication#refresh()

整個容器初始化流程大致能夠分爲12步,想對哪一步驟感興趣的讀者能夠自行決定將其做爲分支入口瞭解其原理。這裏我分析第2步和第11步,也就是IOC最關鍵的流程:建立BeanFactory的流程和Bean初始化的流程。爲了省略篇幅,省略掉了相關干擾項,好比try/catch塊。

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			// 1: 刷新預處理
			// 設置Spring容器的啓動時間,撤銷關閉狀態,開啓活躍狀態。
			// 初始化屬性源信息(Property)
			// 驗證環境信息裏一些必須存在的屬性
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			// 2:
			// a) 建立IOC容器(DefaultListableBeanFactory)
			// b) 加載解析XML文件(最終存儲到Document對象中)
			// c) 讀取Document對象,並完成BeanDefinition的加載和註冊工做
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			// 3: 對IOC容器作一些預處理(設置一些公共屬性)
			prepareBeanFactory(beanFactory);

				// 4:
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// 5:調用BeanFactoryPostProcessor後置處理器對BeanDefinition處理
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				// 6: 註冊BeanPostProcessor後置處理器
				registerBeanPostProcessors(beanFactory);

				// 7: 初始化一些消息源(好比處理國際化的i18n等消息資源)
				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				// 8: 初始化應用事件廣播器
				initApplicationEventMulticaster();

				// 9:初始化一些特殊的bean
				// Initialize other special beans in specific context subclasses.
				onRefresh();
				// 10:註冊一些監聽器
				// Check for listener beans and register them.
				registerListeners();
				// 11:實例化剩餘的單例bean(非懶加載方式)
				// 注意事項: Bean的IOC、ID和AOP都是發生在此步驟
				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);
				// 12: 完成刷新時,須要發佈對應的事件
				// Last step: publish corresponding event.
				finishRefresh();
		}
		//...省略try/catch代碼塊
		
複製代碼

咱們跟進第2步obtainFreshBeanFactory(),這裏主要完成XML文件的解析(最終存儲到Document對象中),讀取Document對象,並完成BeanDefinition的加載和註冊工做,返回一個Bean工廠DefaultListableBeanFactory,讀者的能夠對照着上面的UML類關係圖,找到DefaultListableBeanFactory的位置,體會一下這個類的做用。

咱們接着進入到AbstractRefreshableApplicationContext#refreshBeanFactory

這裏就會建立一個比較重要的容器IOC容器工廠,DefaultListableBeanFactory,咱們配置文件的信息就以BeanDefinition對象形式存放在這裏,咱們關注loadBeanDefinitions(beanFactory);這行代碼,這裏就是加載咱們的配置文件封裝到BeanDefinition並存到DefaultListableBeanFactory的邏輯實現,這裏只是定義了一個鉤子方法,實現主要由子類去實現,有點像設計模式中的抽象模板方法。

protected final void refreshBeanFactory() throws BeansException {
		// 若是以前有IOC容器,則銷燬
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
    // 建立IOC容器,也就是DefaultListableBeanFactory
    DefaultListableBeanFactory beanFactory = createBeanFactory();
    beanFactory.setSerializationId(getId());
    // 設置工廠的屬性:是否容許BeanDefinition覆蓋和是否容許循環依賴
    customizeBeanFactory(beanFactory);
    // 調用BeanDefinition的方法,在當前類中定義了抽象的loadBeanDefinitions方法,具體的實現調用子類容器。
    loadBeanDefinitions(beanFactory); // 鉤子方法
    synchronized (this.beanFactoryMonitor) {
    this.beanFactory = beanFactory;
    }
    //...省略try/catch代碼塊
	}
複製代碼

這裏咱們主要關心xml配置文件對應的實現類,也有註解的形式,感興趣的讀者能夠將此做爲分支進行深刻研究。

咱們進到 AbstractXmlApplicationContext#loadBeanDefinitions

這裏咱們看到了接口隔離設計原則和單一職責原則,初步體會到了定義這麼多的接口的好處。咱們先來看BeanFactory的繼承體系中, DefaultListableBeanFactory是實現了BeanDefinitionRegistry接口,擁有了註冊BeanDefinition的能力,但這裏傳給XmlBeanDefinitionReader這個BeanDefinition閱讀器的只是將BeanDefinitionRegistry這個擁有註冊BeanDefinition功能接口傳入(咱們看XmlBeanDefinitionReader構造函數就知道,public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) ),其餘的能力還在DefaultListableBeanFactory中,這實際上是保護了DefaultListableBeanFactory,體現了接口隔離的效果。

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
		// Create a new XmlBeanDefinitionReader for the given BeanFactory.
		// 建立一個BeanDefinition閱讀器,經過閱讀XML文件,真正完成BeanDefinition的加載和註冊
		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); // 委託給BeanDefinitions閱讀器去加載BeanDefinition loadBeanDefinitions(beanDefinitionReader); } 複製代碼

咱們接着進入到loadBeanDefinitions方法中,

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
		// 獲取資源的定位
		// 這裏getConfigResources是一個空實現,真正實現是調用子類的獲取資源定位的方法
		// 好比:ClassPathXmlApplicationContext中進行了實現
		// 		而FileSystemXmlApplicationContext沒有使用該方法
		Resource[] configResources = getConfigResources();
		if (configResources != null) {
			// XML Bean讀取器調用其父類AbstractBeanDefinitionReader讀取定位的資源
			reader.loadBeanDefinitions(configResources);
		}
		// 若是子類中獲取的資源定位爲空,則獲取FileSystemXmlApplicationContext構造方法中setConfigLocations方法設置的資源
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			// XML Bean讀取器調用其父類AbstractBeanDefinitionReader讀取定位的資源
			reader.loadBeanDefinitions(configLocations);
		}
	}
複製代碼

這裏咱們主要看

reader.loadBeanDefinitions(configLocations),並進入到

public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
		// 獲取在IOC容器初始化過程當中設置的資源加載器
		ResourceLoader resourceLoader = getResourceLoader();
		if (resourceLoader == null) {
			throw new BeanDefinitionStoreException(
					"Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
		}

		if (resourceLoader instanceof ResourcePatternResolver) {
			// Resource pattern matching available.
				Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
				// 委派調用其子類XmlBeanDefinitionReader的方法,實現加載功能
				int count = loadBeanDefinitions(resources);
				if (actualResources != null) {
					Collections.addAll(actualResources, resources);
				}
				if (logger.isTraceEnabled()) {
					logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
				}
				return count;
			}
			// ...省略try/catch代碼塊
}
複製代碼

咱們進入到其子類XmlBeanDefinitionReader#loadBeanDefinitions

這裏會獲取XML文件的InputStream流,並封裝到InputSource中,咱們主要看doLoadBeanDefinitions這個具體的解析過程。

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
		 //...省略若干代碼
			// 將資源文件轉爲InputStream的IO流
			InputStream inputStream = encodedResource.getResource().getInputStream();
				// 從InputStream中獲得XML的解析流
				InputSource inputSource = new InputSource(inputStream);
				if (encodedResource.getEncoding() != null) {
					inputSource.setEncoding(encodedResource.getEncoding());
				}
				// 具體的解析過程
				return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
			}
			//...省略try/catch代碼塊
			
	}
複製代碼

咱們來到XmlBeanDefinitionReader#doLoadBeanDefinitions:

這裏主要是將XML封裝成Document對象,而後對Document對象的解析操做,完成BeanDefinition的加載和註冊工做。通過千辛萬苦,咱們終於來到這一步,不容易啊!

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {

			// 經過DOM4加載解析XML文件,最終造成Document對象
			Document doc = doLoadDocument(inputSource, resource);
			// 經過對Document對象的解析操做,完成BeanDefinition的加載和註冊工做
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
			// .../省略try/catch代碼塊

複製代碼

咱們來看看BeanDefinition是如何註冊的

進入到XmlBeanDefinitionReader#registerBeanDefinitions

這裏 很好地利用了面向對象中單一職責原則,將邏輯處理委託給單一的類進行處理,好比: BeanDefinitionDocumentReader

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
		// 使用DefaultBeanDefinitionDocumentReader實例化BeanDefinitionDocumentReader
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		// 記錄統計前BeanDefinition的加載個數
		int countBefore = getRegistry().getBeanDefinitionCount();
		// 加載及註冊bean
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		// 記錄本次加載的BeanDefinition個數
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}
複製代碼

咱們進入到BeanDefinitionDocumentReader#registerBeanDefinitions

並進入到其默認實現類DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions

protected void doRegisterBeanDefinitions(Element root) {
		// 這裏使用了委託模式,將具體的BeanDefinition解析工做交給了BeanDefinitionParserDelegate去完成
		BeanDefinitionParserDelegate parent = this.delegate;
		this.delegate = createDelegate(getReaderContext(), root, parent);

		//...省略掉了默認命名空間的代碼
		// 在解析Bean定義以前,進行自定義的解析,加強解析過程的可擴展性
		preProcessXml(root); // 鉤子方法
		// 委託給BeanDefinitionParserDelegate,從Document的根元素開始進行BeanDefinition的解析
		parseBeanDefinitions(root, this.delegate);
		// 在解析Bean定義以後,進行自定義的解析,增長解析過程的可擴展性
		postProcessXml(root); // 鉤子方法

		this.delegate = parent;
	}
複製代碼

這裏咱們主要關心parseBeanDefinitions

進入到DefaultBeanDefinitionDocumentReader#parseBeanDefinitions

這裏就比較重要了,遍歷解析Document對象的全部子節點,這裏咱們只關心parseDefaultElement,也就是 bean標籤、import標籤、alias標籤,則使用默認解析規則

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
		// 加載的Document對象是否使用了Spring默認的XML命名空間(beans命名空間)
		if (delegate.isDefaultNamespace(root)) {
			// 獲取Document對象根元素的全部子節點(bean標籤、import標籤、alias標籤和其餘自定義標籤context、aop等)
			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;
					// bean標籤、import標籤、alias標籤,則使用默認解析規則
					if (delegate.isDefaultNamespace(ele)) {
						parseDefaultElement(ele, delegate);
					}
					else { //像context標籤、aop標籤、tx標籤,則使用用戶自定義的解析規則解析元素節點
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			delegate.parseCustomElement(root);
		}
	}
複製代碼

咱們進入到DefaultBeanDefinitionDocumentReader#parseDefaultElement

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		// 解析<import>標籤
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		// 解析<alias>標籤
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		// 解析bean標籤
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			// 遞歸調用
			doRegisterBeanDefinitions(ele);
		}
	}
複製代碼

這裏咱們主要看標籤的解析,其餘的讀者感興趣的話能夠本身去看。

咱們進入到DefaultBeanDefinitionDocumentReader#processBeanDefinition

BeanDefinitionParserDelegate#parseBeanDefinitionElement會解析BeanDefinition,並封裝到BeanDefinitionHolder,

BeanDefinitionReaderUtils#registerBeanDefinition會最終將BeanDefinition註冊到BeanDefinitionRegistry(DefaultListableBeanFactory)中,並存入到map中:private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

感興趣的讀者能夠繼續跟蹤,這裏咱們終於解析完了BeanDefinition。完成了AbstractApplicationContext#refresh() 的第2步:XML文件的解析和BeanDefinition的加載和註冊工做

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		// 解析<bean>標籤,獲取BeanDefinition
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// 註冊最終的BeanDefinition到BeanDefinitionRegistry(DefaultListableBeanFactory)
				// 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));
		}
	}
複製代碼

實例化Bean

咱們來看看AbstractApplicationContext#refresh()的第11步,這步很重要、很重要、很重要。。。

這裏完成了單例Bean的實例化,Bean的IOC、ID和AOP都是發生在這步

AbstractApplicationContext#finishBeanFactoryInitialization

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
//... 省略掉了若干代碼
// Instantiate all remaining (non-lazy-init) singletons.
		// 實例化單例bean
		beanFactory.preInstantiateSingletons();
}
複製代碼

咱們進入到DefaultListableBeanFactory#preInstantiateSingletons

這裏先了解一下,BeanFactory和FactoryBean的區別,

  • BeanFactory是spring頂級接口,是spring基礎容器,它負責管理bean實例。

  • FactoryBean只是spring容器中被管理的一個bean對象,只是說這個bean它的能力就是產生另外的對象。

  • BeanFactory是一個包容萬物的大工廠

  • FactoryBean是一個只能生產指定對象的小工廠,並且這個小工廠還被大工廠給管理。

  • FactoryBean和普通的Bean實例,被Spring管理時,也是區別對待的。經過&前綴來區分FactoryBean和普通的Bean實例

public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		// 觸發全部非懶加載方式的單例bean的建立
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				// 若是bean是一個FactoryBean,則走下面的方法
				if (isFactoryBean(beanName)) {
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						final FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
											((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else { // 普通bean走下面的方法
					getBean(beanName);
				}
			}
		}
		//...省略掉若干代碼
}
複製代碼

這裏咱們走的是普通的Bean

進入AbstractBeanFactory#getBean,

並進入到AbstractBeanFactory#doGetBean

這個方法,主要分爲兩個步驟:

  1. 從緩存中獲取單例Bean,若是獲取到了就檢測,若是獲取出來的Bean是FactoryBean,則須要從FactoryBean實例中產生一個對象
  2. 若是沒有獲取到Bean,則須要經過BeanDefinition來實例化一個Bean返回
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

		// 獲取bean的名稱
		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		// 從緩存中獲取單例bean
		Object sharedInstance = getSingleton(beanName);
		// 若是獲取到單例bean,則走下面代碼
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			// 若是取出來的Bean實例是FactoryBean的Bean實例,則須要從FactoryBean實例中產生一個對象實例
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else { // 若是沒有獲取到單例bean,則走下面代碼
			// Fail if we're already creating this bean instance: // We're assumably within a circular reference.
			// 若是原型模式的Bean發生循環引用,則直接不處理,直接拋異常
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			//...省略了檢測BeanDefinition是否在Factory中的代碼

			try {
				// 獲取實例化的bean的BeanDefinition對象
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				// 檢查該BeanDefinition對象對應的Bean是不是抽象的
				checkMergedBeanDefinition(mbd, beanName, args);
				//...省略檢測代碼

				// Create bean instance.
				// 若是是單例的Bean,看下面代碼
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							// 建立單例Bean的主要方法
							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()) { // 原型
					//...省略了處理原型模式Bean的分支
				}

				else { 
					//...省略了好比處理request、session級別的bean的分支
		    }

		return (T) bean;
	}
複製代碼

咱們主要來看這段代碼(重要):

這裏用到了Java8的lambda表達式

// Create bean instance.
				// 若是是單例的Bean,看下面代碼
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							// 建立單例Bean的主要方法
							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);
				}
複製代碼

進入到DefaultSingletonBeanRegistry#getSingleton

這裏處理了循環依賴的問題,什麼是循環依賴,以及spring如何解決循環依賴,期待我下一篇文章。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		synchronized (this.singletonObjects) {
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				//...省略檢測代碼
				// 建立以前,設置一個建立中的標識
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					// 調用匿名內部類獲取單例對象
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
	       //...省略catch代碼塊
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					// 消除對象建立中的標識
					afterSingletonCreation(beanName);
				}
				// 將產生的單例Bean放入緩存中(總共三級緩存)
				if (newSingleton) {
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}
複製代碼

上面 singletonObject = singletonFactory.getObject();調用的是lambda表達式中的createBean(beanName, mbd, args)方法。

咱們進入到其實現類

AbstractAutowireCapableBeanFactory#createBean

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
      
     //...省略若干代碼塊
     // 完成Bean實例的建立(實例化、填充屬性、初始化)
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}
複製代碼

進入到咱們關心的

AbstractAutowireCapableBeanFactory#doCreateBean

這裏完成完成Bean實例的建立,包括三個步驟:

  1. 實例化

    默認調用無參構造實例化Bean,構造參數依賴注入就是發生在這個步驟

  2. 屬性填充(DI依賴注入發生在此步驟)

    利用反射和內省技術進行屬性設置

  3. 初始化(AOP發生在此步驟)

    也是利用反射調用初始化方法好比

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		// bean初始化第一步:默認調用無參構造實例化Bean
		// 構造參數依賴注入,就是發生在這一步
		if (instanceWrapper == null) {
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		// 實例化後的Bean對象
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		//...省略若干代碼

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		// 解決循環依賴的關鍵步驟
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		// 若是須要提早暴露單例Bean,則將該Bean放入三級緩存中
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			// 將剛建立的bean放入三級緩存中singleFactories(key是beanName,value是FactoryBean)
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			// bean初始化第二步: 填充屬性(DI依賴注入發生在此步驟)
			// 這裏主要分爲兩種狀況:
			// 1.對於非集合類型的屬性,直接使用反射和內省機制去進行屬性設置
			// 2。對於集合類型的屬性,將其屬性值解析爲目標類型的集合後直接賦值給屬性
			populateBean(beanName, mbd, instanceWrapper);
			// bean初始化第三步:調用初始化方法,完成bean的初始化操做(AOP發生在此步驟)
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		//... 省略catch塊代碼

		//...省略若干代碼
		return exposedObject;
	}
複製代碼

到這裏,SpringIOC容器對Bean定義的資源文件的加載、解析和依賴注入已經解析完畢,如今SpringIOC容器中管理了一系列靠依賴關係聯繫起來的Bean,程序不須要應用本身手動建立所需對象,SpringIOC容器會在咱們使用的時候自動爲咱們建立,而且爲咱們注入好相關的依賴,這就是Spring核心功能的控制反轉和依賴注入的相關功能,所謂的反轉,也就是將建立Bean的權利交給spring進行管理。

相關文章
相關標籤/搜索