Spring的主要特性:依賴注入(DI)和麪向切面編程(AOP)
依賴注入
DamselRescuingKnight只能執行RescueDamselQuest探險任務
public class DamselRescuingKnight implements Knight {
private RescueDamselQuest quest;
public DamselRescuingKnight() {
quest = new RescueDamselQuest(); //DamselRescuingKnight 緊密地與RescueDamselQuest 耦合在一起
}
public void embarkOnQuest() throws QuestException {
quest.embark();
}
}
爲DamselRescuingKnight類編寫單元測試出奇的難,必須保證embarkOnQuest()被調用的同時embark()也被調用,沒有哪種簡明的方式能夠實現。
耦合具有兩面性:
①緊密耦合代碼難測試、難複用、難理解,而且會引發連環bug;
②一定程度的耦合又是必須的,完全沒有耦合的代碼什麼也做不了。
BraveKnight足夠靈活,可以接受任何賦予他的探險任務
public class BraveKnight implements Knight {
private Quest quest;//探險類型是Quest接口,能夠響應多種探險實現類
public BraveKnight(Quest quest) {
this.quest = quest; //依賴注入方式之一:構造器注入
}
public void embarkOnQuest() throws QuestException {
quest.embark();
}
}
依賴注入的最大好處:鬆耦合。若一個對象只通過接口來標明依賴關係,那麼這種依賴就能夠在對象本身毫不知情的情況下,用不同的具體實現進行替換。
以下爲實例核心代碼:
-> knights.xml
<bean id="knight" class="com.springinaction.knights.BraveKnight">
<constructor-arg ref="quest" />
</bean>
<bean id="quest" class="com.springinaction.knights.SlayDragonQuest" />
ApplicationContext context =
new ClassPathXmlApplicationContext("knights.xml");//加載spring上下文
Knight(接口) knight = (Knight) context.getBean("knight");
knight.embarkOnQuest();
應用切面
依賴注入讓相互協作的軟件組件保持鬆散耦合,而AOP允許你把遍佈應用各處的功能分離出來形成可重用組件。AOP編程是一項分離關注點的技術。諸如日誌、事務管理和安全的【系統服務】經常融入到自身的核心業務邏輯組件中,這些系統服務通常被稱爲橫切關注點,因爲他們總是跨越系統的多個組件。
示意圖如下:
AOP使這些服務模塊化,並以聲明的方式將它們應用到需要影響的組件中。更高的內聚性,更加關注自身業務。總之AOP確保POJO保持簡單。
沒有使用AOP之前:
public class Minstrel {//詩人類
public void singBeforeQuest() {//探索前(前置通知)
...
}
public void singAfterQuest() {//探索後(後置通知)
...
}
}
public class BraveKnight implements Knight {
private Quest quest;
private Minstrel minstrel;//詩人
public BraveKnight(Quest quest,Minstrel minstrel) {
this.quest = quest;
this.minstrel = minstrel;
}
public void embarkOnQuest() throws QuestException {
minstrel.singBeforeQuest();
quest.embark();
minstrel.singAfterQuest();
}
}
這樣會對BraveKnight類產生侵入。再假如我們有一個不需要吟遊詩人的騎士,那還要考慮minstrel爲null的情況,爲其增加業務邏輯。但使用AOP可以聲明吟遊詩人必須歌頌騎士的探索事蹟,而騎士就不再直接訪問吟遊詩人的方法。
<bean id="knight" class="com.springinaction.knights.BraveKnight">
<constructor-arg ref="quest" />
</bean>
<bean id="quest"
class="com.springinaction.knights.SlayDragonQuest" />
<bean id="minstrel"
class="com.springinaction.knights.Minstrel" /> <!--聲明Minstrel bean-->
<aop:config>
<aop:aspect ref="minstrel">
<aop:pointcut id="embark"
expression="execution(* *.embarkOnQuest(..))" /> <!--聲明切面,切入點id爲embark。expression屬性值採用AspectJ的切點表達式語言-->
<aop:before pointcut-ref="embark"
method="singBeforeQuest"/><!--聲明前置通知-->
<aop:after pointcut-ref="embark"
method="singAfterQuest"/><!--聲明後置通知-->
</aop:aspect>
</aop:config>
Bean應用上下文
在spring應用中,對象由spring容器創建、裝配和管理。
容器是spring框架的核心。spring自帶兩類不同類型的容器。Bean工廠(BeanFactory,比較低級,較少用)、應用上下文(ApplicationContext,一般項目都是用這個容器)。
BeanFacotry是spring中比較原始的Factory。如XMLBeanFactory就是一種典型的BeanFactory。原始的BeanFactory無法支持spring的許多插件,如AOP功能、Web應用等。
ApplicationContext接口,它由BeanFactory接口派生而來,因而提供BeanFactory所有的功能。ApplicationContext以一種更向面向框架的方式工作以及對上下文進行分層和實現繼承,提供了許多豐富的功能,簡化開發,提高開發效率。
三類常見的spring應用上下文:
FileSystemXmlApplicationContext->
從文件系統加載應用上下文
ClassPathXmlApplicationContext->
從類路徑加載應用上下文
XmlWebApplicationContext->
讀取web應用下的XML並加載上下文
ApplicationContext ctx = new FileSystemXmlApplicationContext("C:/XXX.xml");
ApplicationContext ctx = new ClassPathXmlApplicationContext("XXX.xml");
ApplicationContext ctx = new XmlWebApplicationContext("XXX.xml");
Bean生命週期
①spring對bean進行實例化;
②spring將值和引用注入bean對應的屬性中;
③若bean實現了BeanNameAware接口,spring將bean的id傳入setBeanName接口方法;④若bean實現了BeanFactoryAware接口,spring將調用setBeanFactory接口方法,將BeanFactory容器(spring容器)的
實例
傳入;
⑤若bean實現了ApplicationContextAware接口,spring將調用setApplicationContext接口方法,將應用上下文(spring容器)的引用
傳入;
說明
BeanPostProcessor接口包含兩個method。
postProcessBeforeInitialization方法:在Spring調用任何bean的初始化鉤子(例如InitializingBean.afterPropertiesSet或者init方法)之前被調用;
postProcessAfterInitialization方法:Spring在成功完成嵌入初始化以後調用它。
⑥ 若bean實現了BeanPostProcessor接口,先調用postProcessBeforeInitialization接口方法;
⑦若bean實現了InitializingBean接口,會調用afterPropertiesSet接口方法,若使用了init聲明初始化方法也會被調用;
⑧若bean實現了BeanPostProcessor接口,會調用postProcessAfterInitialization接口方法;⑨準備就緒,可被程序使用,一直滯留在上下文中,直到該上下文被銷燬。
Spring模塊
按六個模塊看 Spring的主要模塊分別是核心Spring容器,spring的AOP模塊,數據訪問與集成,web和遠程調用,測試。
- 核心spring容器:容器是spring框架最核心的部分,它負責spring應用中Bean的創建、配置和管理。
- Spring的AOP模塊:在AOP模塊中,spring對面向對象切面編程提供了豐富的支持。這個模塊是spring應用系統開發切面的基礎。
- 數據訪問與集成:使用jdbc編寫代碼通常會導致大量的樣板式代碼,例如獲得數據庫連接、創建語句、處理結果集到最後關閉數據庫連接。Spring的jdbc和dao模塊封裝了這些樣板代碼,使我們的數據庫代碼變得簡單明瞭,還可以避免因爲釋放數據庫資源失敗而引發的問題。該模塊在幾種數據庫服務的錯誤信息之上構建了一個語義豐富的異常層,以後我們再也不需要解釋那些隱晦專有的sql錯誤信息了。
- Web和遠程調用:mvc模式已經被普遍的接受爲一種構建web應用的方法,它有助於將用戶界面邏輯與應用邏輯分離。Spring雖然集成了多種主流的mvc框架,但他的web和遠程調用模塊自帶了一個強大的mvc框架,有助於應用提升web層技術的鬆散耦合。
- 測試:鑑於開發者自測的重要性,spring提供了測試模塊來測試spring應用。
按七個模塊看 組成 Spring 框架的每個模塊(或組件)都可以單獨存在,或者與其他一個或多個模塊聯合實現。每個模塊的功能如下:
- 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要組件是 BeanFactory,它是工廠模式的實現。BeanFactory 使用控制反轉 (IOC) 模式將應用程序的配置和依賴性規範與實際的應用程序代碼分開。
- Spring 上下文:Spring 上下文是一個配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企業服務,例如 JNDI、EJB、電子郵件、國際化、校驗和調度功能。
- Spring AOP:通過配置管理特性,Spring AOP 模塊直接將面向方面的編程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何對象支持 AOP。Spring AOP 模塊爲基於 Spring 的應用程序中的對象提供了事務管理服務。通過使用 Spring AOP,不用依賴 EJB 組件,就可以將聲明性事務管理集成到應用程序中。
- Spring DAO:JDBC DAO 抽象層提供了有意義的異常層次結構,可用該結構來管理異常處理和不同數據庫供應商拋出的錯誤消息。異常層次結構簡化了錯誤處理,並且極大地降低了需要編寫 的異常代碼數量(例如打開和關閉連接)。Spring DAO 的面向 JDBC 的異常遵從通用的 DAO 異常層次結構。
- Spring ORM:Spring 框架插入了若干個 ORM 框架,從而提供了 ORM 的對象關係工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有這些都遵從 Spring 的通用事務和 DAO 異常層次結構。
- Spring Web 模塊:Web 上下文模塊建立在應用程序上下文模塊之上,爲基於 Web 的應用程序提供了上下文。所以,Spring 框架支持與 Jakarta Struts 的集成。Web 模塊還簡化了處理多部分請求以及將請求參數綁定到域對象的工作。
- Spring MVC 框架:MVC 框架是一個全功能的構建 Web 應用程序的 MVC 實現。通過策略接口,MVC 框架變成爲高度可配置的,MVC 容納了大量視圖技術,其中包括 JSP、Velocity、Tiles、iText 和 POI。
總結
Spring致力於簡化企業級java開發,促進代碼鬆散耦合。成功關鍵在於依賴注入和AOP,這兩者是Spring框架最核心的部分。
參考:《Spring實戰(第3版)》
http://blog.csdn.net/liu904139492/article/details/44226985
http://blog.knowsky.com/200197.htm
作者: @nanphonfy
Email: nanphonfy (Nfzone) gmail.com 請將(Nfzone)換成@