深入IOC及其啟動原理

  • 2020 年 11 月 9 日
  • 筆記

IOC總結

1. IOC概述

三個問題:

  1. IOC是什麼
  2. 為什麼用它
  3. 怎麼用

1.1 是什麼?

兩個概念:控制反轉,依賴注入

來看一下傳統的幹活方式:在對象單一職責原則的基礎上,一個對象很少有不依賴其他對象而完成自己的工作,所以這個時候就會出現對象之間的依賴。而體現在我們的開發中,就是需要什麼對象的時候,就創建什麼對象,此時對象創建的控制權在我們自己手裡。當對象創建的太多的時候,就會出現一個對象更改,就得更改所有依賴它的對象,耦合性大。自主性體現的同時也出現了對象耦合嚴重的情況

這個時候,我們就會思考,能不能我們在用的時候直接拿到這個對象去用,而將創建對象的能力交給第三方,這樣我們就不需要關心對象是怎麼創建的了。即將自己的控制權交出去。這就是控制反轉

這個時候,就會有另一個問題產生了,對象怎麼才能直接被我們拿來用呢。對象創建的時候,我們把這個對象注入到這個對象中,然後就可以使用了。這就是依賴注入

另一個問題,耦合性怎麼被解決掉的?通過控制反轉我們僅僅使用了這個對象,如果對象發生了修改,我們僅僅需要修改第三方創建對象的方式即可,這個時候難道還會出現所謂的對象耦合嗎?😄

完成這些工作的就是IOC容器,它幫助我們創建對象,然後在對象被使用的時候,將對象注入到這個對象中。而由於IOC創建對象是通過反射來創建的,所以其速度不如直接new對象


還不理解???放心,聽筆者講一個故事,筆者最喜歡講故事了

前段時間,天氣逐漸回暖,鑒於家裡沒有短袖的情況,筆者只能選擇購買了。這個時候筆者有兩種選擇,第一、去生產衣服的廠家直接去買(便宜);第二、去實體店或者網店購買(較昂貴)。之後,由於筆者屬於宅男大軍的一員,直接網上購物。

這個場景就是一個典型的控制反轉的過程。筆者不需要關注衣服怎麼生產的,而是僅僅去淘寶(IOC容器)上,尋找自己想要的衣服(對象),然後直接拿過來用即可。但是由於存在中間商賺差價,所以價格更貴(時間更長)🙈

最後兩句話:

控制反轉:將自己的控制權交給自己信任的第三方,甲乙之間不存在依賴關係

依賴注入:開放一個端口留給A,然後在需要的時候,將B注入到A中。

1.2 為什麼用

在上面,筆者已經很清晰的描述了為什麼要使用IOC,主要原因就是由於對象之間的耦合。

1.3 怎麼用

1.3.1 XML

通過書寫XML配置文件,向容器中添加需要注入的Bean

1.3.2 Annotation

通過@Configuration註解指定配置類。

2. IOC架構

一個圖搞定,這個就是IOC的架構思路,這不是其執行流程圖

我們接下來一步一步來解讀。

2.1 白話版

在第一章中我們了解了IOC是來幫助我們管理和創建對象的。

這個時候我們需要一個承載我們需要創建信息的容器,即圖中的XML或者註解,那麼有了我們自己的BeanDefiniton信息以後,我們需要一個接口用來讀取這些信息,於是出現了BeanDefinitionReader用來讀取我們自己的Bean信息。

那麼我們需要考慮一個問題了,那麼多的對象怎麼生產呢?

答案就是工廠模式。Spring默認的工廠是DefaultListableBeanFactory,沒錯,Spring中的所有對象(容器對象和我們自己創建的對象)都是由他創建的。大批量生產對象

這個時候又有了一個問題,我們不想通過BeanFactory直接生產了,需要對這個工廠進行一些特定處理,於是出現了BeanFactoryPostProcessor,用來對工廠做一些特定的處理。我們自己可以通過實現這個接口,進行自定義BeanFactory。又有兄弟說了:我想單獨創建一些我喜歡的對象,安排FactoryBean誕生了,它可以幫助我們創建一個我們需要的對象(第四部分詳細解釋他們之間的區別)。

那又有兄弟說了:我想讓統一的對象創建之前按照我的方式進行一些特殊的行為,簡單,安排🙈

BeanPostProcessor出現了,他提供了兩個方法:一個在對象實例化之後初始化之前,執行內部的Before方法,在初始化之後,執行After方法。(Bean生命周期,第四部分詳解

這個時候有兄弟有疑問了,不是說BeanPostProcessor在創建對象之前執行嗎?怎麼是創建完畢以後才執行的Before方法。

如果各位兄弟了解過指令重排序這個概念,那麼一定會聽過一個案例,創建一個對象需要三步

  • 創建空間(實例化)
  • 初始化
  • 賦值

其中在初始化和賦值會出現指令重排序

根據這個點,應該可以get到一個點,實例化和初始化不一樣。

所以又引出了一個點,我們對Bean進行一些操作,怎麼操作,肯定是修改屬性,或者添加一些屬性等等,需要等待其在堆中開闢空間即實例化完成以後執行吧。

所以BeanPostProcessorbefore方法在實例化之後執行,初始化之前執行。

經歷過前面一大堆的操作以後,終於我們的對象進入我們兜里了(容器里)。

關於銷毀,一般情況下我們通過ApplicationContext拿不到其銷毀方法,只能通過其子類實現獲取,關於銷毀同樣的流程,先執行一個銷毀之前的操作,然後再銷毀。

2.2 實際工作流程

看過Spring源碼或者聽過的都知道裏面有一個方法叫做refresh,他完成了好多事情。當然他的行為也代表了整個IOC容器加載和實例化對象的過程。第三章的代碼解讀中我們仔細看

執行過程:

  • 加載配置文件,初始化系統環境Environment接口
  • 準備上下文環境,初始化一些配置資源
  • 創建一個工廠
  • 為工廠添加各種環境
  • 獲取子類自己重寫的BeanFactoryPostProcessor
  • 執行容器和我們自己的BeanFactoryPostProcessor
  • 註冊BeanPostProcessor
  • 國際化處理
  • 轉播器
  • 子類初始化Bean
  • 註冊監聽器,觀察者模式
  • 完成Bean創建
  • 發佈相應的事件,監聽器

3. IOC源碼解讀

寫在之前:IOC的源碼比較複雜,所以個人建議視頻方式學習,大家可以B站搜索閣主梧桐(筆者認為講的不錯的一個解讀),如果大家不喜歡視頻的方式,又想深度學習IOC源碼那麼推薦程序員囧輝它的博客對於IOC的講解非常深入。另外本文接下來的Spring源碼,主要是通過圖示的方法梳理其流程,作者水平有限。如有錯誤請留言。

3.1 上下文配置啟動

在創建ClassPathXmlApplicationContext的時候,構造方法中執行了這些方法。

說白了,加載了一個解析配置文件路徑的加載器;然後又通過系統環境變量拿到這個配置文件,進行一些配置文件的去空格,轉換表達式等等操作(沒有進行解析);最後就是那個被我標成紅色東東,refresh方法中它完成了幾乎所有的工作。下面細聊

3.2 refresh

這個方法幾乎完成了所有的操作,創建工廠,執行Processor等等,實例化對象,開啟事件監聽等等。

接下來細聊

3.3.1 prepareRefresh()

這個方法的主要作用是為應用上下文的刷新做一些準備性的工作。校驗資源文件,設置啟動時間和活躍狀態等。

3.3.2 obtainFreshBeanFactory()

可以get到,它主要就是創建了一個工廠BeanFactory,並且解析了配置文件,加載了Bean定義信息(面試的時候直接答這個點就夠了,如果想說的可以將下面的bean信息加載聊聊)

沒錯,標紅的就是咱接下來細聊的點

這個就是加載配置文件的過程,注意:此時仍然沒有解析,解析在標紅的下面

這個就是讀取的過程,具體解析流程來自parse中,這個直接調用了Java中的解析XML的類庫,有興趣自行翻閱,最後返回了一個Document對象。

通過Document對象,讀取內部的標籤,執行不同的方法,邏輯和MyBatis中解析配置文件的思想相同,大家自行翻閱。

此時所有的Bean定義信息都被保存到了BeanDefinitionRegistry接口,然後走子類DefaultListableBeanFactory工廠的註冊方法

3.3.3 prepareBeanFactory(beanFactory)

BeanFactory準備一些環境,方便在實例化的時候使用,同時添加容器自己的BeanPostProcessor

3.3.4 postProcessBeanFactory

留給子類擴展的BeanFactoryPostProcessor

3.3.5 invokeBeanFactoryPostProcessors(beanFactory)

這個類,涉及到了兩個接口。

  • BeanFactoryPostProcessor
  • BeanDefinitionRegistryPostProcessor接口,這個接口是BeanFactoryPostProcessor的子接口,它的優先級比BeanFactoryPostProcessor更高

它的總體執行流程是:先執行BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor,然後再執行BeanFactoryPostProcessor

下圖是BeanDefinitionRegistryPostProcessor接口的處理過程

BeanFactoryPostProcessor的處理邏輯

總邏輯就是先分類,已經處理過的直接跳過,沒有處理過的,分類處理,邏輯和上面的相同。

3.3.6 registerBeanPostProcessors

這個方法的邏輯和上面的一樣,只不過上面是直接執行了BeanFactoryPostProcessor,而這個僅僅註冊沒執行。

首先拿到工廠中所有的BeanPostProcessor類型的Bean,然後分類處理,排序註冊。

3.3.7 initMessageSource()

執行國際化內容

3.3.8 initApplicationEventMulticaster

創建了一個多播器,為添加Listener提供支持。

主要邏輯:

  • 容器中是否存在applicationEventMulticaster,如果存在直接註冊
  • 如果不存在,創建一個SimpleApplicationEventMulticaster,註冊到容器中。
3.3.9 onRefresh()

子類擴展

3.3.10 registerListeners()

觀察者模式的實現

protected void registerListeners() {
		// 拿到當前容器中的監聽器,註冊到多播器中
		for (ApplicationListener<?> listener : getApplicationListeners()) {
			getApplicationEventMulticaster().addApplicationListener(listener);
		}

		//拿到容器中為監聽器的Bean,註冊
		String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
		for (String listenerBeanName : listenerBeanNames) {
			getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
		}

		// 清空開始的事件,到廣播器中
		Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
		this.earlyApplicationEvents = null;
		if (earlyEventsToProcess != null) {
			for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
				getApplicationEventMulticaster().multicastEvent(earlyEvent);
			}
		}
	}
3.3.11 finishBeanFactoryInitialization

這一部分的內容太多了,所以採用代碼和圖解的方式來講解。

	/**
	 * Finish the initialization of this context's bean factory,
	 * initializing all remaining singleton beans.
	   在上下文工廠中完成所有Bean 的初始化
	 */
	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// 初始化上下文轉換服務Bean
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}

		
        //如果不存在前入值解析器,則註冊一個默認的嵌入值解析器,主要是註解屬性解析
		if (!beanFactory.hasEmbeddedValueResolver()) {
			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
		}

		// 初始化LoadTimeWeaverAware
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}

		// Stop using the temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(null);

		// Allow for caching all bean definition metadata, not expecting further changes.
		beanFactory.freezeConfiguration();

		// Instantiate all remaining (non-lazy-init) singletons.
        //實例化,重點
		beanFactory.preInstantiateSingletons();
	}

下圖是創建Bean的主要流程

按照途中的序號一個一個說:

  1. BeanDefinition是否需要合併。BeanDefinition根據不同類型的配置文件信息,會將Bean封裝到不同的Bean信息定義類中。比如我們常用的配置文件版的GenericBeanDefinition;註解掃描版的ScannedGenericBeanDefinition等等。

而在這個過程中就出現了,父定義和子定義,我們需要在實際處理定義信息的時候進行合併處理,主要有一下三個方面

  • 存在父定義信息,使用父定義信息創建一個RootBeanDefinition,然後將自定義信息作為參數傳入。
  • 不存在父定義信息,並且當前BeanDefinitionRootBeanDefintion類型的,直接返回一份RootBeanDefintion的克隆
  • 不存在父定義信息,並且當前BeanDefintion不是RootBeanDefintiton類型的,直接通過該BeanDefintion構建一個RootBeanDefintion返回

上面的流程也是源碼中的執行流程

  1. isFactoryBean。判斷是否為FactoryBean

簡單介紹一下:FactoryBean是讓開發者創建自己需要Bean接口。內部提供了三個方法

T getObject() throws Exception;//返回的Bean信息
Class<?> getObjectType();//返回的Bean類型
default boolean isSingleton() {return true;}//是否單例

當我們通過GetBean直接該Bean的時候,獲取到的是該工廠指定返回的Bean類型。如果想要獲取該Bean本身,需要通過一個前綴獲得&

@Override
public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
	String beanName = transformedBeanName(name); //解析真正的BeanName
	Object beanInstance = getSingleton(beanName, false);//獲取容器中的bean
	if (beanInstance != null) {//如果容器中存在,直接返回該Bean是否為FactoryBea類型
		return (beanInstance instanceof FactoryBean);
	}
    //沒有Bean信息,檢查這個Bean信息
	if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
			// 從父工廠中獲取
		return 
            ((ConfigurableBeanFactory) getParentBeanFactory()).isFactoryBean(name);
		}
    //MergedBeanDefinition來檢查beanName對應的Bean是否為FactoryBean
		return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
	}

再來看一個點,這個就是從容器中獲取Bean的主要方法,也是解決循環依賴的邏輯

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    //查看當前容器中是否存在該Bean
		Object singletonObject = this.singletonObjects.get(beanName);
    //如果不存在,且當前Bean正在被創建
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
                //從早期的容器中獲取Bean
				singletonObject = this.earlySingletonObjects.get(beanName);
                //如果早期容器也沒有且允許創建早期引用
				if (singletonObject == null && allowEarlyReference) {
                    //獲取該Bean的ObjectFactory工廠
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    //如果當前工廠不為空
					if (singletonFactory != null) {
                        //創建一個對象實例,此時處於半初始化狀態
						singletonObject = singletonFactory.getObject();
                        //添加到早期引用中
						this.earlySingletonObjects.put(beanName, singletonObject);
                        //移除創建早期引用的工廠,因為該Bean已經創建且添加到了早期容器中,不需要再次進行創建了。
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
}

來聊一下它是怎麼解決循環引用的?

它引入了一個三級緩存的概念

/**存放了所有的單例Bean */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** 存放了Bean創建需要的ObejctFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

/** 存放了早期創建的Bean,此時的Bean沒有進行屬性賦值,僅僅通過構造方法創建了一個實例 */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

//正在創建的Bean
private final Set<String> singletonsCurrentlyInCreation =
			Collections.newSetFromMap(new ConcurrentHashMap<>(16));

在發生循環引用的時候,它首先通過ObejctFactory工廠將Bean創建出來,此時的對象並沒有進行屬性賦值,僅僅在堆中開闢了空間。然後將此時的Bean添加到earlySingletonObjects容器里,也就是說這個容器中保存的Bean都是半成品。而在之後的屬性賦值中,由於對象為單例的,所以其引用地址不會發生變化,即對象最終是完整的。

  1. getBean通過這個方法直接創建了所有的對象,這也是Spring最核心的方法了

先來看一下它整體的一個流程

它的主要邏輯是:先拿到當前要實例化的Bean的真實名字,主要是為了處理FactoryBean,拿到以後,從當前容器中看是否已經創建過該Bean,如果存在直接返回。

如果不存在,獲取其父工廠,如果父工廠不為空,而且當前容器中不存在當前Bean的信息,則嘗試從父工廠中獲取Bean定義信息,進行Bean實例化

如果父工廠為空,將當前Bean信息存放到alreadyCreated緩存中。

獲取當前Bean的合併信息(getMergedLocalBeanDefinition),查看當前Bean是否存在依賴,如果存在則判斷當前Bean和依賴Bean是否為循環依賴,如果不是循環依賴則先創建依賴Bean

判斷當前Bean的作用域。

如果當前Bean是單例對象,直接創建Bean實例

如果當前Bean是多例對象,將當前Bean信息添加到正在創建多例緩存中,創建完畢以後移除

如果當前Bean是其他類型,如Requtst,Session等類型,則自定義一個ObejctFacotry工廠,重寫getObject方法,創建對象

對象創建以後,判斷當前對象是否為自己需要的對象,如果是直接返回;如果不是進行類型轉換,如果類型轉換失敗,直接拋異常

接下來看一眼CreateBean的執行

這個方法主要完成的事情是:通過Bean的名字拿到對應的Class對象;如果當前Bean獲取到的Class對象不為空且該RootDefintiton可以直接獲取到該Bean,克隆一份Bean定義信息,方便之後使用。

驗證當前Bean上的@Override信息。執行BeanPostProcessor,返回一個代理對象(如果存在代理的話)

如果不存在代理,則直接創建Bean

接下來我們來聊一下這個玩意——resolveBeforeInstantiation

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
		Object bean = null;
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
			// Make sure bean class is actually resolved at this point.
            //當前定義信息不是合併,且存在Bean增強器
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                //獲取Bean的Class類型
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
                    //如果不為null,則執行前置處理器
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
                        //如果前置處理器不為null,則後置處理器執行,跳過spring默認初始化
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
            //代表已經再實例化之前進行了解析
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

來吧,繼續,看一下那個前置處理器邏輯

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
            //拿到工廠中的所有的BeanPostProcessor
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
                //找到所有我們需要的增強器
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                // 返回一個代理實例
				Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
				if (result != null) {
					return result;
				}
			}
		}
		return null;
	}

後置處理器就不看了,就調用了所有的後置處理器,然後執行了一遍,沒有其他邏輯。

接下來繼續我們的正題:doCreateBean

其大致流程如上圖:

先判斷以後是否單例,然後從FactoryBean緩存中看一下是否存在正在創建的Bean,如果存在拿出,如果不存在則創建一個當前Bean的包裝類實例。然後拿到這個類的實例和實例類型,執行以後後置處理器。

當前Bean是否為單例,是否允許循環依賴,時候正在進行創建,如果是,創建一個當前Bean的ObejctFactory以解決循環依賴的問題

填充Bean的屬性,進行Bean的實例化。

查看早期容器緩存中(緩存中的二級緩存中是否有該Bean)。如果有,則說明存在循環依賴,則進行處理

先看循環依賴吧

if (earlySingletonExposure) {
    //從早期的Bean容器中拿到實例對象,此時的Bean必然存在循環依賴
    Object earlySingletonReference = getSingleton(beanName, false);
    if (earlySingletonReference != null) {
        
        if (exposedObject == bean) {
            exposedObject = earlySingletonReference;
        } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
            
            //獲取依賴的全部Bean信息
            String[] dependentBeans = getDependentBeans(beanName);
            Set < String > actualDependentBeans = new LinkedHashSet < > (dependentBeans.length);
            for (String dependentBean: dependentBeans) {
                //清除這些Bean信息,此時的Bean已經是臟數據了
                if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                    //無法清理存入actualDependentBeans中
                    actualDependentBeans.add(dependentBean);
                }
            }
            if (!actualDependentBeans.isEmpty()) {
                throw new BeanCurrentlyInCreationException
            }
        }
    }
}

// Register bean as disposable.
try {
    registerDisposableBeanIfNecessary(beanName, bean, mbd);
} catch (BeanDefinitionValidationException ex) {
    throw new BeanCreationException(
        mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}

接着來,createBeanInstance

Spring提供了三種方式創建對象的包裝:

  • 通過供給者對象對象直接創建。obtainFromSupplier
  • 通過工廠方法直接創建。
  • 默認創建。
    • 構造方法是否需要自動注入
    • 構造方法不需要自動注入,調用默認的構造方法

這個方法執行完畢以後,你應該知曉的一個點是:此時對象實例已經創建了,剩下的就是執行一系列增強器和初始化方法,屬性填充等等。


我們按照代碼執行順序來,屬性填充即populateBean

這個方法執行邏輯:

首先判斷傳入的Bean是否為null,如果為null則判斷Bean定義信息中是否存在屬性值,如果存在,異常;如果不存在跳過

當前Bean定義信息是否為合併以後的,如果是且此時的工廠中存在InstantiationAwareBeanPostProcessors,那麼在屬性填充之前進行修改Bean的信息

拿到所有的屬性值,解析屬性值的自動注入方式,Type或者Name,進行自動注入

判斷是否存在InstantiationAwareBeanPostProcessors,修改之前設置的屬性

判斷是否存在依賴檢查,檢查依賴

屬性賦值


接下來看執行初始化方法,就是調用BeanPostprocessor,init等方法

這個就是這個方法的執行流程圖,相信到這個地方,大家應該對於為什麼BeanPostProcessor的before方法會在init方法執行了解了。這個方法的作用僅僅是用來進行一個生命周期的打印,對象在之前已經創建了。


接下來看一下銷毀的方法。registerDisposableBeanIfNecessary

對於單例Bean來說,Spring將需要銷毀的Bean存放到了disposableBeans緩存中,通過DisposableBeanAdapter封裝了銷毀Bean

對於其他作用域來說,自定義了銷毀回調函數,不過最後還是封裝為DisposableBeanAdapter

在封裝為DisposableBeanAdapter的過程中,會首先判斷該Bean中是否存在destroy方法,然後給賦值給destroyMethodName變量。再次判斷這個方法的參數,如果參數的個數大於1,則拋出異常

3.3.12 finishRefresh

這個方法進行了一系列的資源清理和

protected void finishRefresh() {
		// 清空上下文資源緩存
		clearResourceCaches();

		// 初始化生命周期處理器
		initLifecycleProcessor();

		// 將已經刷新完畢的處理器傳播(扔到)生命周期處理器中
		getLifecycleProcessor().onRefresh();

		// 推送上下文刷新完畢的時間到相應的監聽器
		publishEvent(new ContextRefreshedEvent(this));

		// Participate in LiveBeansView MBean, if active.
		LiveBeansView.registerApplicationContext(this);
	}

initLifecycleProcessor,這個方法極具簡單,就看一下當前Bean中是否存在生命周期處理器,如果存在直接使用這個,如果不存在則創建一個默認的,並且註冊為一個單例的扔到容器中。

4. 常見題目

4.1 Bean的生命周期?

Spring官方解釋在BeanDefinition接口的注釋里

答:Bean完整的生命周期是:

  • 設置一系列Aware接口的功能
  • 實例化Bean
  • 調用BeanPostProcessorbefore方法
  • 執行InitializingBean接口方法afterPropertiesSet
  • 執行init方法
  • 調用BeanPostProcessorpostProcessAfterInitialization方法
  • 調用DestructionAwareBeanPostProcessors接口的postProcessBeforeDestruction方法
  • 調用destory方法

4.2 FactoryBean和BeanFactory的區別

答:BeanFactorySpring默認生產對象的工廠。

FactoryBeanSpring提供的一個生產特定類型和特定對象的工廠。例如Mybatis-spring中的SqlSessionFactoryBean就是通過這種方法創建的。

4.3 什麼是循環依賴?Spring如何處理循環依賴的?

答:循環依賴是指:在創建A對象的時候需要注入B對象;在創建B對象的時候需要注入A對象,兩者互相依賴。

出現循環依賴有兩種情況:

  • 構造器依賴(無法解決)
  • 屬性注入(可以解決

解決循環依賴,Spring引入了三級緩存的概念。上面的源碼講解中介紹過

  • singletonObjects存放了所有的單例Bean,此時所有的Bean信息都是完整的
  • earlySingletonObjects存放了早期的Bean,此時僅僅創建了一個Bean實例,未進行屬性填充
  • singletonFactories存放了Bean的工廠

Spring通過將創建Bean的工廠暴露出來,然後在出現循環依賴的時候通過這個工廠常見一個bean,然後將這個Bean注入,由於對象是單例的,所以在接下來的屬性填充中,可以保證為同一個對象,至此,循環依賴解除。

使用三太子敖丙的一句話:解決循環依賴的過程就是力扣中的第一題兩數之和的過程

4.4 什麼是IOC

答:IOC存在兩個點:

  • 控制反轉。將常見對象的控制權交給第三方,這裡的第三方就是Spring
  • 依賴注入。在類中需要使用到的對象,全部通過反射從第三方容器注入而不是自己創建。這裡的第三方容器即Spring

4.5 ApplicationContext和BeanFactory的區別

答:

  • ApplicationContext採用了立即加載,即加載配置文件的時候就創建了對象。BeanFactory採用了延時加載的方式,使用的時候才創建。
  • 對於BeanPostProcessorBeanFactoryProcessor而言,BeanFactory是手動註冊,ApplicationContext採用了自動註冊。

4.6 Spring 框架中都用到了哪些設計模式?

答:

  • 單例模式。這個不需要多說
  • 代理模式。AOP使用到的
  • 裝飾着模式。BeanWrapper
  • 工廠模式。BeanFactory,創建對象的時候
  • 模板方法模式。JDBCTemplate
  • 觀察者模式。各種事件監聽
  • ……

更多原創文章和Java系列教程關注公眾號@MakerStack