Spring 面試問題

Q. 對於依賴倒置原則(Dependency Inversion Principle,DIP),依賴注入(Dependency Injection,DI)和控制反轉(Inversion of Control,IoC)容器,你是怎麼理解的?

A.

  • 依賴倒置原則(Dependency Inversion Principle, DIP)。這個設計準則某種程度上和依賴注入模式有些關聯。DIP的出發點是:在應用開發中,高層模塊不應當直接依賴低層模塊。DIP並不意味着依賴注入。這個準則並沒有講到高層模塊如何知道調用哪個低層模塊。不過這一點通過實現工廠模式接口可以間接獲知,或者通過類似Spring框架、Pico容器、Guice或者Apache HiveMind之類的loC容器實現依賴注入從而得知高層模塊調用的具體哪個低層模塊。


pic31.jpg


DIP意味着:

  • 高層模塊不應當依賴低層模塊,它們都應當依賴抽象。

  • 抽象不應該依賴具體實現。具體實現應該依賴抽象。

應用這個準則後,高層模塊並不直接同低層模塊交互,而是通過一個抽象層來跟低層模塊進行交互。這使得需求變更後增加的成本更加靈 活可控。這裏有些實現DIP的示例代碼片段。

首先定義抽象層:

1
2
3
4
5
6
7
8
packageprinciple_dip2;
publicinterfaceAnimalHandler {
publicabstract voidhandle( );
}
packageprinciple_dip2;
publicinterfaceAnimalHelper {
publicabstract voidhelp( );
}

接着是依賴於抽象類而非具體實現的高層代碼。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
packageprinciple_dip2;
publicclassCircusService {
AnimalHandler handler;
publicvoidsetHandler(AnimalHandler handler) {
this.handler = handler;
}
publicvoidshowStarts( ) {
//code omitted for brevity
handler.handle( );
}
}
packageprinciple_dip2;
publicclassTigerHandler implementsAnimalHandler{
AnimalHelper helper;
publicvoidsetHelper(AnimalHelper helper) {
this.helper = helper;
}
publicvoidhandle( ){
//...
helper.help( );
//...
}
}
packageprinciple_dip2;
publicclassTigerHelper implementsAnimalHelper{
publicvoidhelp( ){
//......
}
}
  • 依賴注入模式(Dependency Injection):在運行時將類的依賴注入到代碼中。通過將依賴定義爲接口,並將實現這個接口的實體類注入到主類的構造器中來實現這個模式。這允許程序員在不同的實現之間轉換而不用去修改主類。依賴注入模式可以通過單一責任原則Single Responsibility Principle)SRP來使得代碼高內聚(high cohesion),因爲所依賴的通常都是完成獨立的功能的對象,例如,(通過DAO進行)數據存取或(通過Service和Delegate類實現)業務服務。

  • 控制反轉容器(Inversion of Control Container,IoC),是一個支持依賴注入的容器。這種方式下,可以採用一箇中心容器,例如Spring框架,Guice或者HiveMind,來定義哪個依賴應該使用哪個實體類。Ioc的鬆耦合性可以帶來更多的靈活性,並且在程序運行時更容易去切換到正確的依賴對象上。控制反轉模式的基本概念是,不去實際生成對象,而是去定義如何生成對象。不用直接在代碼中將模塊和服務硬編碼在一起,而是在配置文件中描述哪個模塊需要哪個服務。容器(例如Spring框架這個IoC容器)會負責將這兩者綁定起來。應用IoC的時候,某對象所需的依賴會在創建的時候通過外部實體傳入,這些外部實體用來協調系統中的不同對象。也就是說,依賴是被注入到對象中去的。因此,IoC就是關於一個對象如何獲得其協作對象的引用的一種責任反轉機制。

DIIoC的真正強大之處在於,在運行時而非編譯時綁定類間關係。例如,在Seam框架中,你可以對一個接口進行兩種實現:真正的實現和模擬(mock)的實現,而在運行時根據某個屬性、另一個文件存在與否或者某個優先值去決定真正調用哪一個實現。這尤其當你希望程序在不同場景下表現不同的行爲時,這是非常好用的。DI和IoC的另外一個好處是,使得代碼更容易進行單元測試。當然也有其他一些好處,例如,不用使用工廠或者單例模式就可以實現鬆耦合,其實現方法一致因此適合缺乏經驗的程序員,等等。當然,享受這些好處是要付出代價的,例如系統複雜性會隨之增加,另外在使用時也需要更加小心,不能因爲這個技術受歡迎就濫用,而是在能夠真正體現其優勢的地方纔去使用。

注意:上下文依賴注入(Contexts and Dependency Injection)是用來描述標準依賴注入的一個嘗試。CDI是Java EE 6 stack的一部分,也就是說任何一個運行在Java EE 6兼容容器之上的應用都可以輕鬆使用CDI。Weld就是CDI的一個可參考的實現。

Q. 以你的經驗來看,爲什麼要選擇使用Spring框架呢?

A.

  • Spring採用層次結構,有超過20個模塊可供選用。這就意味着你可以根據需要自由取捨。Spring通過簡單Java對象(Plain Old Java Object,POJO)編程簡化了J2EE。在Spring中J2EE編程並沒有什麼特別的。POJO編程提供了代碼的持續集成能力和易測性。


pic41.jpg



  • Spring框架的核心功能是依賴注入(DI)。DI使得代碼的單元測試更加方便、系統更好維護、代碼也更加靈活。DI代碼自身很容易測試,通過構建實現了應用所需的接口的“模擬”對象就可以進行功能的黑盒測試。DI代碼也更容易複用,因爲其“被依賴的”功能封裝在在定義良好的接口中,允許其他對象根據需要將其插入到所需的對象中,這些對象是在其他應用平臺中進行配置的。DI代碼更加靈活,由於其天生的鬆耦合性,它允許程序員僅需考慮自己所需的接口和其他模塊暴露出來的接口來就可以決定對象之間如何關聯。

  • Spring支持面向切面編程(Aspect Oriented Programming ,AOP),允許通過分離應用業務邏輯和系統服務從而進行內聚性的開發。AOP支持審計(auditing)、蒐集性能和內存指標等功能。

  • Spring還提供了許多實現基本功能的模板類,使得J2EE開發更加容易。例如,JdbcTemplate類和JDBC、JpaTemplate類和JPA,JmsTemplate類和JMS都可以很好地結合起來使用。RestTemplate類非常簡潔,使用這個模板的代碼的可讀性和可維護性也都很好。

  • 儘量把中間層代碼從業務邏輯中剝離出來是很重要的。最好的遠程調用方式就是利用Spring的遠程接口調用,這個功能支持使用任何消息或者遠程技術來完成遠程調用。Apache Camel是一個強大的基於已知的包括Bean集成的企業級集成模式的開源集成框架。Apache Camel設計之初就是爲了儘可能的和Spring框架能夠很好的結合使用。

  • Spring提供了聲明性事務處理,工作調度,身份認證,成熟的MVC web框架以及和其他框架的集成,例如Hibernate、iBatis、JasperReports、JSF、Struts、Tapestry、Seam和Quartz job scheduler等等。

  •  Spring bean對象可以通過Terracotta在不同的JVM之間共享。這就允許使用已有的bean並在集羣中共享 ,將Spring應用上下文事件變爲分佈式事件,還可以通過Spring JMX導出集羣bean,使得Spring應用高可用、集羣化。Spring還可以和其他集羣應用方案集成起來,例如Oracle的Coherance。

  • Spring傾向於使用未檢查異常(unchecked exceptions)和減少不當try,catch和finally代碼塊(或者finally中的try/catch塊)。像JpaTemplate 這樣的Spring模板類會負責關閉或釋放數據庫連接,這避免了潛在的資源泄露問題並提高了代碼的可讀性。

  • 在非Spring或者Guice這種DI框架中,工廠模式和單例模式可以用來提高代碼的鬆耦合度。使用了Spring可以有效避免這些模式的濫用。


Q.根據你的項目經驗,Spring框架的哪些地方是你不喜歡的?你認爲Spring有缺陷嗎?

A.

  • Spring變得過於龐大和笨重。因此,我的建議是不要因爲大家對Spring的讚譽有加而不加思考大肆使用其所有的功能。而是應該去使用Spring中真正對你的項目有用的功能。大多數情況下,從可維護性和不重複造車輪子這方面考慮,使用成熟的Spring這樣的框架比自己從零開始構建一個類似的解決方案要好得多。例如,所有的Spring模板(jdbc,rest,jpa等等)都有如下優勢:構建方式一致,所以你可以跳過這些常規步驟從而將精力放在更重要的業務邏輯上。

  • Spring MVC並不一定是最好的web框架。還有一些其他的,例如,Struts 2,Wicket和JSF等。話雖如此,其實Spring也可以和這些框架(Struts,JSF等)很好的集成起來。

  • XML文件過於臃腫龐大,這一點可以通過其他手段來得到改善。比如使用annotations,JavaConfig或者使用獨立的XML配置文件.


Q.IoC中支持的依賴注入有哪些類型?

A.依賴注入有三種類型:

  • 構造子注入(例如,Spring框架):依賴是通過構造器參數提供的。

  • 設值方法注入(例如,Spring框架):依賴是通過JavaBeans屬性注入的(ex:setter方法)

  • 接口注入(例如,Avalon):注入通過接口完成。


Q.你用過其他依賴注入框架嗎?

A.用過Guice,Hivemind和Seam。

英文原文:java-success,編譯:ImportNew - 鄭雯

原文地址: http://www.importnew.com/1019.html



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章