一文解析Spring IOC面試中常問的那些核心題怔揩!

廣義的 IOC

  1. IoC(Inversion of Control) 控制反轉(zhuǎn)棍丐,即“不用打電話過來,我們會打給你”沧踏。

兩種實現(xiàn): 依賴查找(DL)和依賴注入(DI)歌逢。

IOC 和 DI 、DL 的關(guān)系(這個 DL翘狱,Avalon 和 EJB 就是使用的這種方式實現(xiàn)的 IoC):

  1. DL 已經(jīng)被拋棄秘案,因為他需要用戶自己去是使用 API 進行查找資源和組裝對象。即有侵入性潦匈。

  2. DI 是 Spring 使用的方式阱高,容器負責組件的裝配。

注意:Java 使用 DI 方式實現(xiàn) IoC 的不止 Spring茬缩,包括 Google 的 Guice赤惊,還有一個冷門的 PicoContainer(極度輕量,但只提供 IoC)凰锡。

Spring 的 IoC

Spring 的 IoC 設(shè)計支持以下功能:

  1. 依賴注入
  2. 依賴檢查
  3. 自動裝配
  4. 支持集合
  5. 指定初始化方法和銷毀方法
  6. 支持回調(diào)某些方法(但是需要實現(xiàn) Spring 接口未舟,略有侵入)

其中圈暗,最重要的就是依賴注入,從 XML 的配置上說裕膀, 即 ref 標簽员串。對應 Spring RuntimeBeanReference 對象。

對于 IoC 來說昼扛,最重要的就是容器寸齐。容器管理著 Bean 的生命周期,控制著 Bean 的依賴注入抄谐。

那么渺鹦, Spring 如何設(shè)計容器的呢?

Spring 作者 Rod Johnson 設(shè)計了兩個接口用以表示容器蛹含。

  1. BeanFactory
  2. ApplicationContext

BeanFactory 粗暴簡單海铆,可以理解為就是個 HashMap,Key 是 BeanName挣惰,Value 是 Bean 實例卧斟。通常只提供注冊(put),獲仍髅(get)這兩個功能珍语。我們可以稱之為 “低級容器”。

ApplicationContext 可以稱之為 “高級容器”竖幔。因為他比 BeanFactory 多了更多的功能板乙。他繼承了多個接口。因此具備了更多的功能拳氢。

例如資源的獲取募逞,支持多種消息(例如 JSP tag 的支持),對 BeanFactory 多了工具級別的支持等待馋评。所以你看他的名字放接,已經(jīng)不是 BeanFactory 之類的工廠了,而是 “應用上下文”留特, 代表著整個大容器的所有功能纠脾。

該接口定義了一個 refresh 方法,此方法是所有閱讀 Spring 源碼的人的最熟悉的方法蜕青,用于刷新整個容器苟蹈,即重新加載/刷新所有的 bean。

當然右核,除了這兩個大接口慧脱,還有其他的輔助接口,但我今天不會花太多篇幅介紹他們贺喝。

為了更直觀的展示 “低級容器” 和 “高級容器” 的關(guān)系菱鸥,我這里通過常用的 ClassPathXmlApplicationContext 類宗兼,來展示整個容器的層級 UML 關(guān)系。

有點復雜采缚? 先不要慌针炉,我來解釋一下挠他。

最上面的 BeanFactory 知道吧扳抽?我就不講了。

下面的 3 個綠色的殖侵,都是功能擴展接口贸呢,這里就不展開講。

看下面的隸屬 ApplicationContext 粉紅色的 “高級容器”拢军,依賴著 “低級容器”楞陷,這里說的是依賴,不是繼承哦茉唉。他依賴著 “低級容器” 的 getBean 功能固蛾。而高級容器有更多的功能:支持不同的信息源頭,可以訪問文件資源度陆,支持應用事件(Observer 模式)艾凯。

通常用戶看到的就是 “高級容器”。 但 BeanFactory 也非常夠用啦懂傀!

左邊灰色區(qū)域的是 “低級容器”趾诗, 只負責加載 Bean,獲取 Bean蹬蚁。容器其他的高級功能是沒有的恃泪。例如上圖畫的 refresh 刷新 Bean 工廠所有配置。生命周期事件回調(diào)等犀斋。

好贝乎,解釋了低級容器和高級容器,我們可以看看一個 IoC 啟動過程是什么樣子的叽粹。說白了糕非,就是 ClassPathXmlApplicationContext 這個類,在啟動時球榆,都做了啥朽肥。(由于我這是 interface21 的代碼,肯定和你的 Spring 4.x 系列不同)持钉。

下圖是 ClassPathXmlApplicationContext 的構(gòu)造過程衡招,實際就是 Spring IoC 的初始化過程。

注意每强,這里為了理解方便始腾,有所簡化州刽。

這里再用文字來描述這個過程:

  1. 用戶構(gòu)造 ClassPathXmlApplicationContext(簡稱 CPAC)

  2. CPAC 首先訪問了 “抽象高級容器” 的 final 的 refresh 方法,這個方法是模板方法浪箭。所以要回調(diào)子類(低級容器)的 refreshBeanFactory 方法穗椅,這個方法的作用是使用低級容器加載所有 BeanDefinition 和 Properties 到容器中。

  3. 低級容器加載成功后奶栖,高級容器開始處理一些回調(diào)匹表,例如 Bean 后置處理器⌒桑回調(diào) setBeanFactory 方法袍镀。或者注冊監(jiān)聽器等冻晤,發(fā)布事件苇羡,實例化單例 Bean 等等功能,這些功能鼻弧,隨著 Spring 的不斷升級设江,功能越來越多,很多人在這里迷失了方向 :)攘轩。

簡單說就是

  1. 低級容器 加載配置文件(從 XML叉存,數(shù)據(jù)庫,Applet)撑刺,并解析成 BeanDefinition 到低級容器中鹉胖。

  2. 加載成功后,高級容器啟動高級功能够傍,例如接口回調(diào)甫菠,監(jiān)聽器,自動實例化單例冕屯,發(fā)布事件等等功能寂诱。

所以,一定要把 “低級容器” 和“高級容器” 的區(qū)別弄清楚安聘。不能一葉障目不見泰山痰洒。

好,當我們創(chuàng)建好容器浴韭,就會使用 getBean 方法丘喻,獲取 Bean,而 getBean 的流程如下:

從圖中可以看出念颈,getBean 的操作都是在低級容器里操作的泉粉。其中有個遞歸操作,這個是什么意思呢?

假設(shè):當 Bean_A 依賴著 Bean_B嗡靡,而這個 Bean_A 在加載的時候跺撼,其配置的 ref = “Bean_B” 在解析的時候只是一個占位符,被放入了 Bean_A 的屬性集合中讨彼,當調(diào)用 getBean 時歉井,需要真正 Bean_B 注入到 Bean_A 內(nèi)部時,就需要從容器中獲取這個 Bean_B哈误,因此產(chǎn)生了遞歸哩至。

為什么不是在加載的時候,就直接注入呢黑滴?因為加載的順序不同憨募,很可能 Bean_A 依賴的 Bean_B 還沒有加載好紧索,也就無法從容器中獲取袁辈,你不能要求用戶把 Bean 的加載順序排列好,這是不人道的珠漂。

所以晚缩,Spring 將其分為了 2 個步驟:

  1. 加載所有的 Bean 配置成 BeanDefinition 到容器中,如果 Bean 有依賴關(guān)系媳危,則使用占位符暫時代替荞彼。

  2. 然后,在調(diào)用 getBean 的時候待笑,進行真正的依賴注入鸣皂,即如果碰到了屬性是 ref 的(占位符),那么就從容器里獲取這個 Bean暮蹂,然后注入到實例中 —— 稱之為依賴注入寞缝。
    可以看到,依賴注入實際上仰泻,只需要 “低級容器” 就可以實現(xiàn)荆陆。

這就是 IoC

所以 ApplicationContext refresh 方法里面的操作不只是 IoC集侯,是高級容器的所有功能(包括 IoC)被啼,IoC 的功能在低級容器里就可以實現(xiàn)。

總結(jié)

說了這么多棠枉,不知道你有沒有理解Spring IoC浓体? 這里小結(jié)一下:IoC 在 Spring 里,只需要低級容器就可以實現(xiàn)辈讶,2 個步驟:

  1. 加載配置文件命浴,解析成 BeanDefinition 放在 Map 里。

  2. 調(diào)用 getBean 的時候荞估,從 BeanDefinition 所屬的 Map 里咳促,拿出 Class 對象進行實例化稚新,同時,如果有依賴關(guān)系跪腹,將遞歸調(diào)用 getBean 方法 —— 完成依賴注入褂删。

上面就是 Spring 低級容器(BeanFactory)的 IoC。

至于高級容器 ApplicationContext冲茸,他包含了低級容器的功能屯阀,當他執(zhí)行 refresh 模板方法的時候,將刷新整個容器的 Bean轴术。同時其作為高級容器难衰,包含了太多的功能。一句話逗栽,他不僅僅是 IoC盖袭。他支持不同信息源頭,支持 BeanFactory 工具類彼宠,支持層級容器鳄虱,支持訪問文件資源,支持事件發(fā)布通知凭峡,支持接口回調(diào)等等拙已。

可以預見,隨著 Spring 的不斷發(fā)展摧冀,高級容器的功能會越來越多倍踪。

誠然,了解 IoC 的過程索昂,實際上為了了解 Spring 初始化時建车,各個接口的回調(diào)時機。例如 InitializingBean楼镐,BeanFactoryAware癞志,ApplicationListener 等等接口,這些接口的作用框产,筆者之前寫過一篇文章進行介紹凄杯,有興趣可以看一下,關(guān)鍵字:Spring 必知必會 擴展接口秉宿。

但是請注意戒突,實現(xiàn) Spring 接口代表著你這個應用就綁定死 Spring 了!代表 Spring 具有侵入性描睦!要知道膊存,Spring 發(fā)布時,無侵入性就是他最大的宣傳點之一 —— 即 IoC 容器可以隨便更換,代碼無需變動隔崎。而現(xiàn)如今今艺,Spring 已然成為 J2EE 社區(qū)準官方解決方案,也沒有了所謂的侵入性這個說法爵卒。因為他就是標準虚缎,和 Servlet 一樣,你能不實現(xiàn) Servlet 的接口嗎钓株?: -)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末实牡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子轴合,更是在濱河造成了極大的恐慌创坞,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件受葛,死亡現(xiàn)場離奇詭異题涨,居然都是意外死亡,警方通過查閱死者的電腦和手機奔坟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門携栋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來搭盾,“玉大人咳秉,你說我怎么就攤上這事⊙煊纾” “怎么了澜建?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長蝌以。 經(jīng)常有香客問我炕舵,道長,這世上最難降的妖魔是什么跟畅? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任咽筋,我火速辦了婚禮,結(jié)果婚禮上徊件,老公的妹妹穿的比我還像新娘奸攻。我一直安慰自己,他們只是感情好虱痕,可當我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布睹耐。 她就那樣靜靜地躺著,像睡著了一般部翘。 火紅的嫁衣襯著肌膚如雪硝训。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天,我揣著相機與錄音窖梁,去河邊找鬼赘风。 笑死,一個胖子當著我的面吹牛纵刘,可吹牛的內(nèi)容都是我干的贝次。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼彰导,長吁一口氣:“原來是場噩夢啊……” “哼蛔翅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起位谋,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤山析,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后掏父,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體笋轨,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年赊淑,在試婚紗的時候發(fā)現(xiàn)自己被綠了爵政。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡陶缺,死狀恐怖钾挟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情饱岸,我是刑警寧澤掺出,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站苫费,受9級特大地震影響汤锨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜百框,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一闲礼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧铐维,春花似錦柬泽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至棠众,卻和暖如春琳疏,著一層夾襖步出監(jiān)牢的瞬間有决,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工空盼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留书幕,地道東北人。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓揽趾,卻偏偏與公主長得像台汇,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子篱瞎,可洞房花燭夜當晚...
    茶點故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 2.1 我們的理念是:讓別人為你服務 IoC是隨著近年來輕量級容器(Lightweight Container)的...
    好好學習Sun閱讀 2,702評論 0 11
  • 1苟呐、葉片的質(zhì)地 膜質(zhì):葉片薄而半透明,如半夏俐筋。有的膜質(zhì)葉干薄而脆牵素,不呈綠色稱干膜質(zhì):如麻黃的鱗片葉。 草質(zhì):葉片薄...
    灃郡梧桐閱讀 2,049評論 0 5
  • 我很開心澄者。笆呆。。因為真的好累粱挡。赠幕。。询筏。打工……結(jié)束了榕堰。。屈留。局冰。這幾天就像夢……結(jié)束了,夢醒了灌危,也有笑,也很歡樂過……但是...
    凉沉閱讀 204評論 0 1