java程序員面試必備:初探spring

java程序員面試必備:初探spring

現在的Java程序員趕上了好時候。在將近20年的歷史中,Java的發展歷經沉浮。儘管有很多為人詬病的產品,例如applets、EJB、Java Data Object(JDO)和數不清的日誌框架,Java還是發展為一個龐大且豐富的開發平臺,很多企業級應用都是基於JVM平臺構建。Spring是JVM開發平臺中的一顆明珠。

Spring最開始出現的目的是替代企業級開發框架EJB,相比EJB,Spring提供更輕量和更易用的編程模型。Spring的重要特點是非侵入式增強POJO(plain old java object)的能力。

在後續的發展過程中,EJB也效仿Spring的做法提供了簡單的以POJO為中心的編程模型,現在的EJB框架也擁有依賴注入(DI)和麵向切面編程(AOP)能力,可以論證是受Spring成功的影響。

儘管J2EE一直在追趕Spring的發展,但是Spring本身也沒有停止進步。現在,Spring在一些J2EE剛剛涉入或者完全沒有涉入的領域飛速發展:移動開發、社交API整合、NoSQL數據庫、雲計算和大數據。就目前來看,Spring的未來一片光明。

重要的事情再強調一遍:現在的Java程序員趕上了好時候。

這篇文章會從一個比較高的層次探索Spring,介紹Spring框架解決了哪些主要問題。

1.1 簡化Java開發

Spring是一種開源框架,由Rod Johnson發明,並在其著作《Expert One-on-One:J2EE設計與開發》。Spring的初衷是降低企業級開發的複雜性,並試圖通過POJO對象實現之前EJB這類重型框架才能實現的功能。Spring不僅僅對服務端開發有用,任何Java應用都可受益於Spring的簡潔、易測試和低耦合等特性。

Spring框架中使用beans或JavaBeans來表示應用程序中的組件,但這並不意味著該組件必須嚴格滿足Java Bean的規範。

Spring做了很多事情,但是歸根到底是一些基本的思路,而所有這些思路最終都導向Spring的使命:簡化Java開發

Spring通過下列四種策略來簡化Java開發:

  • 基於POJO的輕量級、最小侵入式開發;

  • 通過依賴注入和麵向接口編程實現松耦合;

  • 通過面向切面編程和模板消除樣板式代碼(boierplate code)

幾乎Spring的每條特性都可以追溯到這四條策略之一,接下來分別對這四條策略進行闡述,並給出具體的代碼說明Spring如何簡化Java開發。

1.1.1 激發POJO的能力

如果你做Java開發足夠久,你應該遇到過很多會束縛程序員能力的開發框架,這些框架要求程序員繼承框架提供的類或者實現它提供的接口,例如EJB框架中的session beans,另外,在EJB之前的很多框架中也有類似的侵入式編程模型,如Struts、WebWork、Tapestry等等。

Spring儘量避免讓自己的API汙染你的應用代碼。Spring幾乎不會強制要求開發人員實現某個Spring提供的接口或者繼承某個Spring提供的類,在Spring應用中的Java類看起來和普通類一樣,不過,Spring現在經常使用註解來修飾Java類,但是這個類還是一個POJO。

舉個代碼例子說明,看如下的HelloWorldBean

java程序員面試必備:初探spring

可以看出,這就是一個簡單的Java類-POJO,沒有什麼特殊的標誌表明它是一個Spring組件。Spring這種非侵入式編程模型使得這個類在Spring和非Spring框架下具備相同的功能。

儘管形式非常簡單,POJO的能力值卻可能非常高,例如Spring可以通過依賴注入編織這些POJOs來激發POJO的能力。

1.1.2 依賴注入

依賴注入聽起來比較嚇人,貌似一種非常複雜的編程技術或者設計模式。實際上依賴注入並不複雜,通過在工程中應用依賴注入技術,可以得到更簡單、更容易理解和測試的代碼。

How DI works

除了Hello-world級別的程序,稍微複雜一點的Java應用都需要多個類配合實現功能。一般而言,每個類自己負責獲取它要合作的類對象的引用,這會導致代碼高度耦合且難以測試。

首先看如下代碼:

java程序員面試必備:初探spring

可以看出,DamselRescuingKnight在它的構造函數中創建了自己的Quest實例——RescueDamselQuest實例,這使得DamselRescuingKnight與RescueDamselQuest緊密耦合,如果需要刺殺Damsel,則這個刀可以使用,但是如果需要刺殺恐龍,則這個刀就派不上用場了。

更糟的是,給DamselRescuingKnight寫單元測試很不方便,在這個測試中,你必須確認:當調用knight的emarkOnQuest函數時,quest的embark函數也正確調用,但這並不容易。

耦合是一頭雙頭怪:一方面,緊耦合的代碼難以測試、難以複用並且難以理解,並且經常陷入“修復一個bug但引入一個新的bug”的開發怪圈中;另一方面,應用程序必須存在適當的耦合,否則該應用無法完成任何功能。總之,耦合是必要的,但是應該控制組件之間的耦合程度。

通過使用依賴注入(DI)技術,對象之間的依賴關係由Spring框架提供的容器進行管理,而不需要某個對象主動創建自己需要的引用,如下圖所示:

java程序員面試必備:初探spring

依賴注入的作用

再看一個BraveKnight類的例子:

java程序員面試必備:初探spring

該對象不再侷限於一種quest實例,在構造過程中利用構造函數的參數傳入quest實例,這種類型的依賴注入稱為構造注入。

還有一點需要注意,使用接口定義quest實例,這就是面向接口編程,使得BraveKnight不再侷限於某種特定的Quest實現,這就是DI帶來的最大的好處——松耦合。

實現依賴注入

在上述例子代碼可以看出,Spring相當於將依賴注入的位置從BraveKnight類中剝離出來,那麼具體的依賴注入代碼如何寫呢?開發人員如何規定給BraveKnight注入哪個Quest實現,例如SlayDragonQuest?

java程序員面試必備:初探spring

在Spirng框架中,最通用的方法是通過寫XML配置文件來定義組件之間的依賴關係,如下所示:

java程序員面試必備:初探spring

在這個xml配置文件中分別定義了BraveKnight和SlayDragonQuest兩個bean:在BraveKnightbean的定義中,通過構造器函數傳入一個SlayDragonQuest的引用;在SlayDragonQuest的定義中,通過SpEL語言將System.out傳入它的構造函數。

Spring 3.0引入了JavaConfig,這種寫法比xml文件的好處是具備類型安全檢查,例如,上面XML配置文件可以這麼寫:

java程序員面試必備:初探spring

不論是基於XML的配置還是基於Java文件的配置,都由Spring框架負責管理beans之間的依賴關係。

啟動依賴注入

在Spring應用中,由application context負責加載beans,並將這些beans根據配置文件編織在一起。Spring框架提供了幾種application context的實現,如果使用XML格式的配置文件,則使用ClassPathXmlApplicationContext;如果使用Java文件形式的配置文件,則使用AnnotationConfigApplicationContext。

java程序員面試必備:初探spring

上述代碼中,根據KnightConfig.java文件創建Spring應用上下文,可以把該應用上下文看成對象工廠,來獲取idknight的bean。

1.1.3 切面編程

依賴注入(DI)實現了模塊之間的松耦合,而利用面向切面編程(AOP)可以將涉及整個應用的基礎功能(安全、日誌)放在一個可複用的模塊中。

AOP是一種在軟件系統中實現關注點分離的技術。軟件系統由幾個模塊構成,每個模塊負責一種功能,不過在系統中有些需求需要涉及到所有的模塊,例如日誌、事務管理和安全等。如果將這些需求相關的代碼都分散在各個模塊中,一方面是不方便維護、另一方面是與原來每個模塊的業務邏輯代碼混淆在一起,不符合單一職責原則。

  • 實現系統級別處理的代碼分散在多個子模塊中,這意味著如果要修改這些處理代碼,則要在每個模塊中都進行修改。即使將這些代碼封裝到一個模塊中,在沒給個子模塊中只保留對方法的調用,這些方法調用還是在各個模塊中重複出現。

  • 業務邏輯代碼與非核心功能的代碼混淆在一起。例如,一個添加address book的方法應該只關心如何添加address book,而不應該關心該操作是否安全或者是否能夠實現事務處理。

下面這張圖可以體現這種複雜性,左邊的業務邏輯模塊與右邊的系統服務模塊溝通太過密切,每個業務模塊需要自己負責調用這些系統服務模塊。

java程序員面試必備:初探spring

業務邏輯模塊與系統服務模塊過度交互

可以將切面想象為覆蓋在一些業務模塊上的毯子,如下圖所示。在系統中有一些模塊負責核心的業務邏輯,利用AOP可以為所有這些模塊增加額外的功能,而且核心業務模塊無需知道切面模塊的存在。

java程序員面試必備:初探spring

切面就像毯子一樣覆蓋在幾個核心業務模塊之上

AOP實踐

繼續上面的例子,如果需要一個人記錄BraveKnight的所作所為,下面代碼是該日誌服務:

java程序員面試必備:初探spring

然後在XML文件中定義Minstrel對應的切面:

java程序員面試必備:初探spring

在這個配置文件中增加了aop配置名字空間。首先定義Minstrel的bean,然後利用標籤定義aop相關的配置;然後在節點中引用minstrel,定義方面;aspect負責將pointcut和要執行的函數(before、after或者around)連接在一起。

還有一種更先進的寫法,利用註解和Java配置文件,可以參考aop docs

Spring框架中的一些子模塊也是基於AOP實現的,例如負責事務處理和負責安全的模塊。


分享到:


相關文章: