兩種實(shí)現(xiàn): 依賴(lài)查找(DL)和依賴(lài)注入(DI)。
IOC 和 DI 、DL 的關(guān)系(這個(gè) DL,Avalon 和 EJB 就是使用的這種方式實(shí)現(xiàn)的 IoC):
DL 已經(jīng)被拋棄,因?yàn)樗枰脩?hù)自己去是使用 API 進(jìn)行查找資源和組裝對(duì)象。即有侵入性。
注意:Java 使用 DI 方式實(shí)現(xiàn) IoC 的不止 Spring,包括 Google 的 Guice,還有一個(gè)冷門(mén)的 PicoContainer(極度輕量,但只提供 IoC)。
Spring 的 IoC 設(shè)計(jì)支持以下功能:
其中,最重要的就是依賴(lài)注入,從 XML 的配置上說(shuō), 即 ref 標(biāo)簽。對(duì)應(yīng) Spring RuntimeBeanReference 對(duì)象。
對(duì)于 IoC 來(lái)說(shuō),最重要的就是容器。容器管理著 Bean 的生命周期,控制著 Bean 的依賴(lài)注入。
那么, Spring 如何設(shè)計(jì)容器的呢?
Spring 作者 Rod Johnson 設(shè)計(jì)了兩個(gè)接口用以表示容器。
BeanFactory 粗暴簡(jiǎn)單,可以理解為就是個(gè) HashMap,Key 是 BeanName,Value 是 Bean 實(shí)例。通常只提供注冊(cè)(put),獲?。╣et)這兩個(gè)功能。我們可以稱(chēng)之為 “低級(jí)容器”。
ApplicationContext 可以稱(chēng)之為 “高級(jí)容器”。因?yàn)樗?BeanFactory 多了更多的功能。他繼承了多個(gè)接口。因此具備了更多的功能。
例如資源的獲取,支持多種消息(例如 JSP tag 的支持),對(duì) BeanFactory 多了工具級(jí)別的支持等待。所以你看他的名字,已經(jīng)不是 BeanFactory 之類(lèi)的工廠了,而是 “應(yīng)用上下文”, 代表著整個(gè)大容器的所有功能。
該接口定義了一個(gè) refresh 方法,此方法是所有閱讀 Spring 源碼的人的最熟悉的方法,用于刷新整個(gè)容器,即重新加載/刷新所有的 bean。
當(dāng)然,除了這兩個(gè)大接口,還有其他的輔助接口,但我今天不會(huì)花太多篇幅介紹他們。
為了更直觀的展示 “低級(jí)容器” 和 “高級(jí)容器” 的關(guān)系,我這里通過(guò)常用的 ClassPathXmlApplicationContext 類(lèi),來(lái)展示整個(gè)容器的層級(jí) UML 關(guān)系。
有點(diǎn)復(fù)雜? 先不要慌,我來(lái)解釋一下。
最上面的 BeanFactory 知道吧?我就不講了。
下面的 3 個(gè)綠色的,都是功能擴(kuò)展接口,這里就不展開(kāi)講。
看下面的隸屬 ApplicationContext 粉紅色的 “高級(jí)容器”,依賴(lài)著 “低級(jí)容器”,這里說(shuō)的是依賴(lài),不是繼承哦。他依賴(lài)著 “低級(jí)容器” 的 getBean 功能。而高級(jí)容器有更多的功能:支持不同的信息源頭,可以訪問(wèn)文件資源,支持應(yīng)用事件(Observer 模式)。
通常用戶(hù)看到的就是 “高級(jí)容器”。 但 BeanFactory 也非常夠用啦!
左邊灰色區(qū)域的是 “低級(jí)容器”, 只負(fù)責(zé)加載 Bean,獲取 Bean。容器其他的高級(jí)功能是沒(méi)有的。例如上圖畫(huà)的 refresh 刷新 Bean 工廠所有配置。生命周期事件回調(diào)等。
好,解釋了低級(jí)容器和高級(jí)容器,我們可以看看一個(gè) IoC 啟動(dòng)過(guò)程是什么樣子的。說(shuō)白了,就是 ClassPathXmlApplicationContext 這個(gè)類(lèi),在啟動(dòng)時(shí),都做了啥。(由于我這是 interface21 的代碼,肯定和你的 Spring 4.x 系列不同)。
下圖是 ClassPathXmlApplicationContext 的構(gòu)造過(guò)程,實(shí)際就是 Spring IoC 的初始化過(guò)程。
注意,這里為了理解方便,有所簡(jiǎn)化。
這里再用文字來(lái)描述這個(gè)過(guò)程:
用戶(hù)構(gòu)造 ClassPathXmlApplicationContext(簡(jiǎn)稱(chēng) CPAC)
CPAC 首先訪問(wèn)了 “抽象高級(jí)容器” 的 final 的 refresh 方法,這個(gè)方法是模板方法。所以要回調(diào)子類(lèi)(低級(jí)容器)的 refreshBeanFactory 方法,這個(gè)方法的作用是使用低級(jí)容器加載所有 BeanDefinition 和 Properties 到容器中。
簡(jiǎn)單說(shuō)就是:
低級(jí)容器 加載配置文件(從 XML,數(shù)據(jù)庫(kù),Applet),并解析成 BeanDefinition 到低級(jí)容器中。
所以,一定要把 “低級(jí)容器” 和“高級(jí)容器” 的區(qū)別弄清楚。不能一葉障目不見(jiàn)泰山。
好,當(dāng)我們創(chuàng)建好容器,就會(huì)使用 getBean 方法,獲取 Bean,而 getBean 的流程如下:
從圖中可以看出,getBean 的操作都是在低級(jí)容器里操作的。其中有個(gè)遞歸操作,這個(gè)是什么意思呢?
假設(shè):當(dāng) Bean_A 依賴(lài)著 Bean_B,而這個(gè) Bean_A 在加載的時(shí)候,其配置的 ref = “Bean_B” 在解析的時(shí)候只是一個(gè)占位符,被放入了 Bean_A 的屬性集合中,當(dāng)調(diào)用 getBean 時(shí),需要真正 Bean_B 注入到 Bean_A 內(nèi)部時(shí),就需要從容器中獲取這個(gè) Bean_B,因此產(chǎn)生了遞歸。
為什么不是在加載的時(shí)候,就直接注入呢?因?yàn)榧虞d的順序不同,很可能 Bean_A 依賴(lài)的 Bean_B 還沒(méi)有加載好,也就無(wú)法從容器中獲取,你不能要求用戶(hù)把 Bean 的加載順序排列好,這是不人道的。
所以,Spring 將其分為了 2 個(gè)步驟:
加載所有的 Bean 配置成 BeanDefinition 到容器中,如果 Bean 有依賴(lài)關(guān)系,則使用占位符暫時(shí)代替。
所以 ApplicationContext refresh 方法里面的操作不只是 IoC,是高級(jí)容器的所有功能(包括 IoC),IoC 的功能在低級(jí)容器里就可以實(shí)現(xiàn)。
說(shuō)了這么多,不知道你有沒(méi)有理解Spring IoC? 這里小結(jié)一下:IoC 在 Spring 里,只需要低級(jí)容器就可以實(shí)現(xiàn),2 個(gè)步驟:
加載配置文件,解析成 BeanDefinition 放在 Map 里。
上面就是 Spring 低級(jí)容器(BeanFactory)的 IoC。
至于高級(jí)容器 ApplicationContext,他包含了低級(jí)容器的功能,當(dāng)他執(zhí)行 refresh 模板方法的時(shí)候,將刷新整個(gè)容器的 Bean。同時(shí)其作為高級(jí)容器,包含了太多的功能。一句話,他不僅僅是 IoC。他支持不同信息源頭,支持 BeanFactory 工具類(lèi),支持層級(jí)容器,支持訪問(wèn)文件資源,支持事件發(fā)布通知,支持接口回調(diào)等等。
可以預(yù)見(jiàn),隨著 Spring 的不斷發(fā)展,高級(jí)容器的功能會(huì)越來(lái)越多。
誠(chéng)然,了解 IoC 的過(guò)程,實(shí)際上為了了解 Spring 初始化時(shí),各個(gè)接口的回調(diào)時(shí)機(jī)。例如 InitializingBean,BeanFactoryAware,ApplicationListener 等等接口,這些接口的作用,筆者之前寫(xiě)過(guò)一篇文章進(jìn)行介紹,有興趣可以看一下,關(guān)鍵字:Spring 必知必會(huì) 擴(kuò)展接口。
但是請(qǐng)注意,實(shí)現(xiàn) Spring 接口代表著你這個(gè)應(yīng)用就綁定死 Spring 了!代表 Spring 具有侵入性!要知道,Spring 發(fā)布時(shí),無(wú)侵入性就是他大的宣傳點(diǎn)之一 —— 即 IoC 容器可以隨便更換,代碼無(wú)需變動(dòng)。而現(xiàn)如今,Spring 已然成為 J2EE 社區(qū)準(zhǔn)官方解決方案,也沒(méi)有了所謂的侵入性這個(gè)說(shuō)法。因?yàn)樗褪菢?biāo)準(zhǔn),和 Servlet 一樣,你能不實(shí)現(xiàn) Servlet 的接口嗎?: -)
創(chuàng)新互聯(lián)www.cdcxhl.cn,專(zhuān)業(yè)提供香港、美國(guó)云服務(wù)器,動(dòng)態(tài)BGP最優(yōu)骨干路由自動(dòng)選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機(jī)房獨(dú)有T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進(jìn)行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動(dòng)現(xiàn)已開(kāi)啟,新人活動(dòng)云服務(wù)器買(mǎi)多久送多久。
文章題目:一文解析SpringIOC面試中常問(wèn)的那些核心題!-創(chuàng)新互聯(lián)
URL分享:http://aaarwkj.com/article24/jdjce.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供域名注冊(cè)、品牌網(wǎng)站建設(shè)、網(wǎng)站排名、品牌網(wǎng)站設(shè)計(jì)、定制網(wǎng)站、網(wǎng)站設(shè)計(jì)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容