一直以來,SpringFramework 做爲 Java 企業級開發的老大哥,面試中也常被問到。雖然說有些基礎性的問題可能不那麼特別被面試官和求職者重視,但若是真的問起來,能不能回答的準確、全面、有深度,仍是很容易體現出水平的。面試
在接下來的一個系列中,我會慢慢盤點一些 Spring 中常見但很差回答全面的問題,跟小夥伴們分享。編程
本文主題:Spring 的 IOC 如何回答的儘量全面、準確、有深度。架構
這是一個看上去特別簡單、感受很無腦的問題,不少求職者在回答這個問題時會不加思考、快速回答出一個很簡單但同時也沒有什麼含量的答案。app
試問一句,親,你在作名詞翻譯嗎?框架
就算真的是在作名詞翻譯,也不該該只是把這個簡稱的全稱解釋出來就完事吧,好歹的展開解釋點東西也好吧,做爲面試官不該該只想聽到這麼一點點吧。學習
這裏面大致上把 IOC 的核心思想解釋出來了:對象間的依賴關係的維護權利發生了轉移,可是請小夥伴們注意,咱們在問 IOC ,這個問題僅僅是問 IOC 自己,與具體的技術無關。IOC 不止有 Spring ,只是當下最強大的、使用最廣的是 Spring 而已。ui
因此小夥伴們在回答理論、概念等問題時,不要直接在概念解釋中提到具體的技術,技術都是概念和理論的落地實現,不止一種。單把一種拉出來,面試官可能會以爲:你是否是隻知道這個?翻譯
該答案僅供參考,可根據自身的知識儲備動態調整。設計
IOC 全名控制反轉 Inverse of Control,它是一種編程原則,它的設計和架構能夠實現組件間的解耦,核心思想是將控制權轉移出去。code
這裏面提到了幾個點:
若是對 IOC 的實現不是特別瞭解,或者只是用 SpringFramework 用的太習慣了,亦或是刻板的學習 SpringFramework ,那這個答案一般會是這樣的:
若是回答出這個答案,而面試官碰巧也跟你同樣,那恭喜你「瞎貓碰到死耗子」了!由於這個回答真的大錯特錯啊,IOC 不止有 DI 的!
正確的回答應該是:
上面已經介紹過了,IOC 僅僅是一種思想,它的意圖是想讓對象間的依賴控制發生轉換。用過 SpringFramework 的小夥伴都知道,你沒有在哪一個地方見過直接寫 IOC 的代碼,都是由一些實現方式來體現 IOC 的。
若是按照上面這樣回答,可能會引來下面一個問題:
針對這個問題,最好不要一上來就搬出代碼解釋,最好是先理論後代碼。
通常狀況下,對比依賴查找和依賴注入,一般能夠從如下幾個維度對比:
依賴查找 | 依賴注入 | |
---|---|---|
實現方式 | 使用上下文(容器)主動獲取 | 依賴上下文被動接收 |
做用目標 | 一般是方法體內的局部變量,也能夠是對象成員 | 一般是對象成員 |
API依賴 | 依賴 IOC 框架的 API(必須操縱容器的 API ) | 能夠不依賴(暴露 setter 方法便可) |
applicationContext.getBean(beanName) | public void setXXX() { ... } |
真的不會有小夥伴只能答出 ApplicationContext
吧,一開始學的時候應該知道還有個 BeanFactory
吧。這是 SpringFramework 中兩個核心的 IOC 容器的抽象。BeanFactory
僅僅是提供了一個容器管理的基本能力,ApplicationContext
在此基礎上作了更加完善、強大的擴展。具體的對比能夠參照下表:
Feature | BeanFactory |
ApplicationContext |
---|---|---|
Bean instantiation/wiring —— Bean的實例化和屬性注入 | Yes | Yes |
Integrated lifecycle management —— 生命週期管理 | No | Yes |
Automatic BeanPostProcessor registration —— Bean後置處理器的支持 |
No | Yes |
Automatic BeanFactoryPostProcessor registration —— BeanFactory後置處理器的支持 |
No | Yes |
Convenient MessageSource access (for internalization) —— 消息轉換服務(國際化) |
No | Yes |
Built-in ApplicationEvent publication mechanism —— 事件發佈機制(事件驅動) |
No | Yes |
下面提供一個比較完整的示例答案,小夥伴們能夠根據本身的知識儲備和理解,調整這裏面的一些描述細節:
BeanFactory
接口提供了一個抽象的配置和對象的管理機制,ApplicationContext
是 BeanFactory
的子接口,它簡化了與 AOP 的整合、消息機制、事件機制,以及對 Web 環境的擴展( WebApplicationContext
等),BeanFactory
是沒有這些擴展的。
ApplicationContext
主要擴展瞭如下功能:(括號內的部分是解釋擴展功能的一些簡單描述或者原理底層實現,能回答出來更好)
AnnotationAwareAspectJAutoProxyCreator
做用於 Bean 的初始化以後 )BeanDefinition
、Environment
、註解等 )Resource
抽象 )ApplicationEvent
、ApplicationListener
)LocaleResolver
)Environment
抽象(SpringFramework 3.1之後)注意這個問題也是與 SpringFramework 無關的,注入的方式自己就應該是依賴注入的實現,至於框架的代碼,那是人家對於這個方式的落地。
可從如下幾個維度對比:
注入方式 | 被注入成員是否可變 | 是否依賴IOC框架的API | 使用場景 |
---|---|---|---|
構造器注入 | 不可變 | 否(xml、編程式注入不依賴) | 不可變的固定注入 |
參數注入 | 不可變 | 是(只能經過標註註解來侵入式注入) | 一般用於不可變的固定注入 |
setter注入 | 可變 | 否(xml、編程式注入不依賴) | 可選屬性的注入 |
基本上問這個問題的話,還可能會繼續問另外一個問題:
「莽夫」應聘者一看終於來開放式問題了,趕忙開始自由發揮了:
我以爲參數注入好,由於我寫習慣了,給參數打註解多舒服啊!
你是這麼說了,面試官咋想:就這?就這???進而對你的印象可能就會有所減分了。
這種問題,除了要表述主觀見解以外,更多的是要根據一些既有的論述來輔助你的觀點,最好的論述那必定是官方文檔了。
SpringFramework 的官方文檔在不一樣的版本推薦的注入方式是不一樣的:
相信大多數小夥伴都能答出 @Autowired
和 @Resource
吧,若是答出這兩個,那證實你應該用過,也會用。但你能回答出 @Inject
,證實你對這些注入的註解確實有瞭解。做爲應聘者,在回答問題時必定是回答的儘量全面爲好,下面對這幾種註解做一個對比:
註解 | 注入方式 | 是否支持@Primary | 來源 | Bean不存在時處理 |
---|---|---|---|---|
@Autowired | 根據類型注入 | 是 | SpringFramework原生註解 | 可指定 required=false 來避免注入失敗 |
@Resource | 根據名稱注入 | 否 | JSR250規範 | 容器中不存在指定Bean會拋出異常 |
@Inject | 根據類型注入 | 是 | JSR330規範 ( 須要導jar包 ) | 容器中不存在指定Bean會拋出異常 |
跟上面差很少,若是問到了這個問題,那就有可能繼續被問到下面一個問題:
可能大多數小夥伴都能答出如下幾種解決方案:
@Resource
:根據名稱指定注入的 Bean@Qualifier
:配合 @Autowired
註解使用,若是被標註的成員 / 方法在根據類型注入時發現有多個相同類型的 Bean ,則會根據該註解聲明的 name 尋找特定的 bean@Primary
:配合 @Bean
註解使用,若是有多個相同類型的 Bean 同時註冊到 IOC 容器中,使用 @Autowired
、@Inject
註解時會注入標註 @Primary
註解的 bean其實你還能夠提另一種方案:把注入的字段名與 bean 的名稱保持一致,這樣也能夠解決注入時報不惟一 Bean 的問題。
以上幾個問題是關於 SpringFramework 與 IOC 部分的一些常見問題,卻是問題都不太陌生,可是小夥伴們想回答的全面、有深度,仍是須要下下功夫的。但願小夥伴們能有所收穫,在面試中流利回答,斬獲 offer !
問題整理不易,不點個贊支持一下做者嗎?(可憐巴巴)