程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Apache Geronimo和Spring 框架,第4部分

Apache Geronimo和Spring 框架,第4部分

編輯:關於JAVA

混合使用Spring AOP和Spring Web Flow

簡介:本系列教程共分為 6 個部分,這是其中的第 4 部分,介紹了 Spring AOP 模塊提供的面向方 面編程(Aspect-Oriented Programming,AOP)支持。通過本教程,您將會了解 Spring 框架如何簡化使 用 AOP 的過程,會看到 Spring Web Flow (SWF) 模塊,並了解如何以 XML 配置文件格式聲明性地定義 應用程序的 Web 流程。您還將看到 Apache Geronimo Web Console 如何使創建及管理數據庫變得更容易 —— 所有操作均無需重新啟動服務器。

開始之前

本系列教程適合於需要了解 Spring 框架的更多信息以及如何在 Apache Geronimo 應用服務器上使用 Spring 框架的強大功能的 Java™ EE 開發人員。

關於本系列教程

本系列教程共分為 6 個部分,向您介紹了 Spring 框架及 Spring 框架怎樣 與 Geronimo 結合使用。我們將從檢驗各種 Spring 框架方法及其怎樣與 Geronimo 服務器結合使用入手 。在整個系列教程中,您將開發和部署個人電話本應用程序。該應用程序包括以下功能:

顯示電 話本

顯示每個條目的詳細信息

向電話本中添加一個新條目

編輯、修改和刪除條目

向條目中添加更多詳細信息,例如主電子郵件地址

第 1 部分 介紹了 Spring 框架的各個 模塊,並介紹了每個模塊與在 Geronimo 應用服務器上開發 Java EE 應用程序的關系。該部分還說明了 Spring 框架所基於的方法。

第 2 部分 介紹了如何使用 Spring 框架在 Geronimo 上構建第一個 骨架系統應用程序。

在 第 3 部分 中,您將采用通過 Apache Derby 數據庫添加 Java 數據庫連 接 (JDBC™) 支持來擴展在第 2 部分中獲得的 Geronimo 應用程序。您還將了解如何將對象關系映 射集成到使用 iBatis 的應用程序中。

在第 4 部分中,您將面對 Spring 面向方面編程 (AOP) 和 Spring Web 框架。使用 Spring AOP,任何受 Spring 框架管理的對象都可變為面向方面的,並且本 教程利用了通過 Spring AOP 提供的聲明式事務管理服務。

第 5 部分介紹了 Spring Model-View-Controller (MVC)。該教程向您介紹了 Spring MVC 框架及 Web 視圖,使您可以了解 Spring MVC 的入門知識。

在本教程結束的第 6 部分,介紹了如何通過 Spring 框架使用 JavaServer Page™(JSP™)、Velocity、Tile 和 PDF 導出功能。您將使 用和體驗 Spring MVC 內置的各種 Web 視圖。

關於本教程

在 第 3 部分 中,擴展了電話 本應用程序,使其從 Derby 數據中動態讀取數據;並且您看到了動態更改數據源而不碰一行代碼是多麼 簡單。使用了 Spring 框架提供的 DAO 和 ORM 模塊來擴展應用程序,並且還了解了如何將其部署到 Geronimo 上。

在本教程中,將通過引入事務把應用程序帶入到下一個級別,事務是一組可恢復的 動作,其保證的輸出要麼是采取了所有動作,要麼是未采取任何動作(如 “漫游 Web 服務原子事 務操作” [developerWorks,2004 年 9 月] 文章所述)。Spring AOP 模塊是隨 Spring 框架分發 預先打包而來的,並且事實上它也是核心模塊之一。您將看到 Spring 如何支持方面、連接點、建議和切 入點等 AOP 概念,然後再將把這些概念引入應用程序中。您將向應用程序中添加一個新頁面以添加新條 目,從而把事務引入到應用程序中。

您還將了解如何使用 SWF 模塊明確定義應用程序的流程。隨 著應用程序復雜度的增加,管理頁面的浏覽流程就變得更難,而 SWF 能夠緩解這種痛苦。

先決條 件

本教程假定您熟悉面向對象的編程 (OOP) 並且熟知 J2EE 和 Java EE 術語。了解面向方面編 程更佳,但不作硬性要求。但是,您必須熟悉 AOP 基本概念並了解基本的 XML 語義。本教程涉及到了一 些 AOP 概念並會嘗試簡要加以介紹,但您的主要目的是要了解 Spring AOP。

系統要求

您 的系統需要至少滿足以下要求才能繼續學習本系列教程

The Spring Framework, Version 1.2.8 —— 具有所有依賴性的壓縮文件。

Apache Geronimo 1.1 —— Geronimo 是 Apache 的 J2EE 認證應用服務器。

Spring Web Flow —— SWF 是 Spring 框架的 一個獨立模塊,並且需要單獨下載。本教程使用版本 1.0-rc3。

Apache Derby 數據庫 —— 本教程使用 Derby,該數據庫是開源的輕量級數據庫。Derby 是嵌入到 Geronimo 1.1 裡的,因此不需要再單獨安裝。

Apache Ant —— 確保正確配置 Ant 並且其 /bin 目 錄位於 Path 系統變量中。

Java 1.4.2 —— 確保 Java 安裝並運行在系統中。

以下是安裝和配置開發、部署和運行示例應用程序所需的軟件的指導信息。

Spring 框架和 Geronimo 安裝 —— 為了使樣例代碼能夠運行,需要安裝運行 Geronimo 和 Spring 框架。有關安裝指南,請參閱 第 2 部分。

Spring Web Flow —— SWF 模 塊是一個獨立的 API。您將使用版本 1 的發行測試版 3(SWF 版本 1-rc3)。將需要使用此次下載附帶 的 JAR 文件。下載名為 spring-webflow-1.0-rc3.zip 的壓縮文件,並將其保存到硬盤某個位置。下載 完後,將壓縮文件解壓縮到應用程序所在的驅動器中(例如,我把它安裝到了驅動器 K: 中)。解壓縮該 文件應當會創建一個名為 spring-webflow-1.0-rc3 的目錄(在我的驅動器中,SWF 的安裝目錄是 K:\spring-webflow-1.0-rc3)。此時,您不需要為 SWF 做任何配置。

Derby 數據庫 —— Geronimo 1.1 預打包附帶的 Derby 數據庫安裝不需要任何特殊配置。您將使用在 第 2 部分 中創建的表,因此請參考該教程以獲得創建及填充本教程所需的數據庫表的步驟。

Spring AOP 和 Spring Web Flow 簡介

在此部分中,將從更深層次向您介紹 AOP、Spring AOP 模塊和 Spring SWF 模塊。

AOP 的基礎知識

AOP 是 Spring 框架的主要組件之一,它基於把橫切 性對象分離為關注點或方面的原理。如 Graham O'Regan 在其文章 “Introduction to Aspect- Oriented Programming”是這樣解釋的:“面向方面編程 (AOP) 是面向對象的 (OO) 編程的 補充,它允許開發人員動態地修改靜態 OO 模型以創建一個可以不斷成長以滿足新需求的系統。就像現實 世界中的對象可以在其生命周期內更改狀態一樣,應用程序也可以隨著開發過程的深入而采用新特性。 ”

幾乎所有現實的軟件系統都有若干個關注點,這些關注點橫跨了多個模塊。實現這些關注 點的面向對象的技術並不總是能提供最理想且清晰的解決方案。AOP 方法可以減輕這種痛苦,它允許將此 類關注點設計為方面。橫切性關注點的最簡單示例是日志記錄和事務。這兩個關注點可以跨越多個模塊並 且使用 OO 設計方法,您可能會因為要為每個模塊定義事務管理而感到有些麻煩,也可能會在使用單個事 務模塊時遇到同步問題。通過使用 AOP 方法,您可以將其定義為方面,這些方面可以被任何需要使用該 方面的模塊共享,並且不需要擔心管理或事務問題。

下面是 AOP 的一些核心概念:

方面 (Aspect):方面是可影響其核心關注點的編程模塊的一部分。它類似於 OO 術語中的類。日志記錄和事務 都是 J2EE 和 Java EE 應用程序中的橫切性關注點的示例。

聯結點 (Join point):定義為程序 執行時主程序和方面相遇的任何邏輯點。此類聯結點的示例包括方法調用和異常。在 Spring AOP 中,一 個聯結點總是一次方法調用。

建議 (Advice):在 AOP 術語中,建議被定義為一項應當在特殊聯 結點上采取的操作。這些操作可以是方法調用、過程或拋出異常。在 AOP 中有各種建議,其中 before、 after 和 around 是三個主要類型。

切入點 (Pointcut):指定建議何時應當觸發的聯結點集合。 Spring AOP 允許將切入點定義為正則表達式。

目標對象 (Target object):被建議的對象並且包 含聯結點。

AOP 代理 (AOP proxy):由 AOP 框架創建的對象,用於實現 AOP 關注點,包括建議 。在 Spring AOP 中,這可以是 JDK 動態代理或 cglib 代理。

織入 (Weaving):定義為聚合所 有方面以創建被建議的對象。Spring AOP 在運行時執行織入。

不同的建議類型包括:

Around 建議:這是圍繞聯結點的一種建議。在 AOP 中,聯結點通常是方法調用。它可以控制程 序的執行,並且可以定義邏輯判斷執行是應當繼續執行,還是應當采取另一條路徑。這種控制功能使得此 建議被廣泛應用到了 AOP 應用程序中。

Before 建議:這是在聯結點之前執行的建議。但是,它 沒有像 Around 建議一樣擁有的對程序流程的控制。

After 建議:類似於 Before 建議,只不過 在這種情況下是在聯結點正常執行完後才執行該建議。這種建議也不能像 Around 建議一樣可以控制流程 。

Throws 建議:Spring AOP 允許在方法(聯結點)拋出異常時定義此類特殊建議。

Spring AOP

上一部分介紹了幾種基本的 AOP 術語。現在,讓我們來看看 Spring AOP 中 的等效術語。Spring 框架目前支持 AOP 的概念集,范圍從切入點到建議。

使用 Spring 作為建 議程序或攔截程序來實現方面。

在 Spring AOP 中,聯結點始終是方法調用。

Spring AOP 為作為攔截程序對象的所有 AOP 建議提供了實現。

Spring AOP 支持使用正則表達式聲明性地定 義切入點。

在 Spring 中,AOP 代理將是 JDK 動態代理或 cglib 代理。

圖 1 顯示了 Spring AOP 如何支持此處定義的概念。

圖 1. Spring AOP 中的 AOP 概念

使用示例電話本應用 程序,您將看到如何使用 Spring AOP 來定義建議、切入點和建議程序等 AOP 概念。示例還將使用依賴 性插入,向您展示如何將這些方面動態插入對象中。

然後介紹由 Spring 提供的事務管理。事務 管理將在內部使用 Spring AOP 以實現其目標。最後將擴展電話本應用程序聲明性地使用此事務。

Spring Web Flow

根據 Spring 框架的官方文檔,“SWF 是專注於在 Web 應用程序 內定義用戶界面流程的產品”。換言之,SWF 將以一種高度可配置且可重用的方式定義此流程。系 統允許捕捉獨立工作流程並在各種環境下加以重用。

用 SWF 定義工作流程

下面是使用當 前技術定義工作流程會遇到的一些問題:

當前技術處理小型且較簡單的導航工作流程很輕松,但 隨著 Web 應用程序變得越來越大越來越復雜,流程管理開始四分五裂。

不能在各種環境中輕松地 重用工作流程,因為流程都是寫死的。

Spring SWF 通過允許在配置文件中聲明性地定義工作流程 來嘗試解決這些問題。這樣您就可以在各種場景中使用這些工作流程。當 Web 應用程序具有一個像向導 一樣的流程時,這最有幫助。

在本教程的稍後部分,將使用 SWF 聲明性地定義電話本應用程序的 流程。還要把在 AOP 部分中定義的方面與 SWF 整合到一起來演示 SWF 的完整功能。

用 Spring AOP 擴展電話本應用程序

在此部分中,將討論到如何將 Spring AOP 與一個方法標記的方面結合 使用。應用程序將使用建議,並會給出定義為方法標記程序或跟蹤程序的切入點。還會介紹建議程序中調 用了哪些方法以及每個建議程序類中的執行流程。稍後事務也將被引入到此應用程序中,您將看到如何聲 明性地定義應用程序的流程。所有工作都將在 XML 文件中完成。

這兩個版本的應用程序都將使用 在 第 3 部分 中定義的 Spring JDBC 類以供數據庫調用。

工作區的目錄結構

圖 2 展示 了應用程序的布局。下載本教程附帶的源壓縮文件並將其解壓縮到硬盤驅動器中。

本教程涉及到 了此處所示的所有目錄及文件。

圖 2. 解壓縮源文件後得到的應用程序目錄結構

定義 Add New Entry 頁面

需要做的第一件事是為應用程序定義 Add New Entry 頁面。 該頁面將在一張表單中包含構成電話本條目的所有字段。此表單上的提交操作將把一個新條目添加到電話 本數據庫中。

完成此操作後,將在應用程序中引入和定義方法標記的方面。如先前所述,方法標 記程序方面可被視為方法跟蹤的方面。基本想法是通過在每個聯結點處放置有意義的消息來理解應用程序 中的 Spring AOP 執行流程。

將所支持的類用於 Spring AOP 支持的建議是十分直觀的。了解方 面的一種方法是在應用程序中定義方法標記的方面。雖然它的功能不是很多,但卻展示了 AOP 的強大。

下一步將是把另一個方面 —— 事務 —— 引入應用程序中。Spring 將通 過允許您在應用程序中聲明性地定義此類事務,再次展示其威力和簡單性。您不需要更改任何代碼。只需 對此事務聲明性地循環執行數據庫調用,Spring 將在成功時把事務提交到數據庫,或在滿足任意一個已 定義的失敗條件時將事務回滾。

改進當前的電話本應用程序

圖 3 展示了 Geronimo 中的 事件流程,第 3 部分 中所述。

圖 3. 如何使對 home-aop.jsp 的請求在 Geronimo 應用服務器 上得到處理

現在來看一看 Spring AOP 支持的三種不同的建議。

事件的 Before 建議流程

此處要為標記方面定義一個用於實 現 MethodBeforeAdvice 的類。MethodBeforeAdvice 是 Spring AOP 提供用於實現 AOP 的 Before 建議 結構的一個接口類。需要實現此類的 before() 方法,並且 Spring AOP 框架將確保在實際的方法調用前 在運行時先調用此方法。下一部分中的順序圖可以更清晰地說明此問題。

另外,還將在 ApplicationContext.xml 文件中引入 Bean 以將此建議應用到目標對象 PhonebookDataProvider 中。此 Bean 還將為 Spring AOP 定義切入點以將此建議應用到目標對象的所有方法中。

Spring 使用代 理模式為基於 ApplicationContext.xml 文件中所做的配置的應用程序提供 AOP 工具。

圖 4 概 括了執行 Before 建議時 Spring 容器裡的事件序列。

圖 4. 定義 Before 建議後的事件序列

如您在 圖 4 的序列圖中所見,SpringAOProxy 是 ProxyFactoryBean 的一個實例,它負責在切入點處截取執行,然後 將特定的建議應用到目標對象上。在這種情況下,首先將在 Spring AOP 的 BeforeAdvice 類的實現中調 用 before() 方面。然後通過在 PhonebookAdapter 類中調用實際的 getPhonebookEntries() 方法來結 束。

事件的 After 建議流程

類似於 Before 建議,此處將定義一個可以實現 Spring AOP 提供的 AfterReturningAdvice 接口的類,以實現 AOP 的 After 建議結構。

圖 5 中描繪的事件 流程與 Before 建議的基本一樣,惟一的不同是目標對象中的實際方法是在應用 After 建議之前調用的 。

換言之,先調用 getPhonebookEntries() 方法,然後 SpringAOProxy 調用 afterReturning() 方法。

圖 5. After 建議的事件序列

事件的 Around 建議 流程

這是 AOP 中最有趣且使用最為廣泛的建議。此建議與其他兩種建議之間的主要差別在於在實 現此建議時可以實施更多控制,因為執行流程將停在由 Advice 類實現的 invoke() 方法中。這就是此建 議被稱為 主動 建議,而其他建議被稱為 被動 建議的原因。

Around 建議專門用於在調用前後實 現自定義行為。它們負責選擇是返回自己的返回值繼續執行操作,還是拋出異常切換到其他執行路徑。

Around 建議在 Spring AOP 中被定義為攔截程序。攔截程序是攔截方法並拋出異常以取得程序執 行控制的類。圖 6 展示了如何為應用程序實現 Around 建議。

圖 6. Around 建議的事件執行

從圖中可以看到,當 Spring 看到一個 Around 建議時,它將在 MethodInterceptor 接口(實現此 AOP 結構的接口)的實現 上調用 invoke() 方法。只需注意必須在 MethodInvocation 對象上顯式調用 proceed() 方法,以在目 標對象上執行該方法。

如果對應用程序開發進行更深層次的鑽研,以上定義的所有流程將會更有 意義。

插入 Spring AOP 支持的事務管理

應用程序的下一個邏輯步驟是將事務管理引入其 中。

聲明性事務管理特性是由 Spring 框架中的 Spring AOP 啟用的。雖然此特性使用 AOP,但 它非常明晰以至於用戶不需要了解 AOP,並且無需更改任何代碼就可以將事務引入到應用程序中。

這裡將使用 TransactionProxyFactoryBean 來創建事務性代理以將事務方面引入應用程序。此 Bean 只是 Spring 的一般 ProxyFactoryBean 的一特例。此 Bean 還將自動創建 TransactionInterceptor 並將其與該代理對象連接起來。

然後,將在必須應用此事務方面的方法 上聲明性地定義切入點。該定義有三個必須指定的主屬性:

transactionManager:要使用的 PlatformTransactionManager 實現(例如,DataSourceTransactionManager 實例)

target:應 為其創建事務代理的目標對象

transactionAttributes:每個目標方法名稱(或方法名稱模式)的 事務屬性(例如,傳播行為和 readOnly 標志)

應用程序將使用 Spring 框架附帶的 JDBC DataSourceTransactionManager。target 是服務對象 PhonebookDataProvider 的接口定義。此處將為應 用程序的 add 方法定義事務屬性。

事務性代理將實現目標的接口;在本例中,為 PhonebookDataProvider 類。這是為此類定義接口的主要原因。

應用程序的數據模型定義和數據 庫設置

在嘗試訪問數據庫前,必須確保數據庫已正確設置。這裡將使用在第 3 部分中創建的同一 個數據庫。因此如果遵循本系列教程的 第 3 部分 中的指導信息進行了操作,則應該已全部設定完畢; 如果沒有遵循上述指導信息,則必須返回並完成第 3 部分,然後才能繼續本教程。

准備好數據庫 中的數據後,可以繼續進行應用程序處理。根據先前部分中的建議,需要先定義 Add New Entry 頁面。 然後從最簡單的方面 —— 方法標記(或方法跟蹤)—— 開始,接下來把事務聲 明性地添加到應用程序中。稍後您將看到如何使用 SWF 聲明性地定義相同的導航流程。

定義 Add New Entry 頁面

需要使用此頁面將導航流程添加到應用程序中以及顯示 Spring 框架的事務管理 特性。此頁面的 JSP 非常簡單,只有一張表單和幾個動作。您可以在 <WORKSPACE>/ phonebook\web\WEB-INF/jsp 目錄中查看這段代碼。圖 7 顯示了運行此頁面在浏覽器中會看到的一個結 果畫面。當您在應用程序主頁中單擊 Add an Entry 按鈕時將調用此頁面。

圖 7. 應用程序的 Add New Entry 頁面

此時,所需的應用程 序的視圖部分就准備好了。下一步要做的是引入方面。

引入 AOP 方面

在此部分中,將定 義接口並將涉及 Before 建議、After 建議和 Around 建議類。然後將構建、部署並在 Geronimo 中運行 電話本應用程序。

在電話本中實現跟蹤方面

用於定義方面和事務管理的 AOP 代理將實現 目標對象的接口:PhonebookDataProvider 。因此就需要為服務類定義接口。

回想一下在 第 3 部分 中定義的 PhonebookDataProvider 類。該類用作客戶機使用的服務類,並且完成了制作數據庫連接 和將結果返回給客戶機的所有苦活。該類由 JSP 實例化以從應用程序中獲取數據。將同樣使用這個類引 入跟蹤方面,但由 Spring AOP 與接口協作。因此需要完成的第一項工作是為此類編寫接口。

清 單 1 顯示了 IPhonebookDataProvider 接口。該接口中包含了將要開發的應用程序部分所需的所有方法 。JSP 將調用 getEntries()。

清單 1. 應用程序的 PhonebookDataProvider 接口

/**
 * IPhonebookDataProvider.java
 * This class defines the  methods to be used by the PhonebookDataProvider class.
 *
 * @author  Arun Chhatpar
 */ 
public interface IPhonebookDataProvider {
  public  List getPhonebookEntries() throws Exception;

  public PhonebookEntry  getPhonebookEntry(int entryID, int rowID) throws Exception;

  public int  addEntry(PhonebookEntry pe) throws Exception;
}

此類沒有多少代碼,只 有方法定義。有了接口之後,就可以讓服務類來實現該接口。

PhonebookDataProvider 實現新接 口

PhonebookDataProvider 將實現新定義的接口。此處的大部分函數與在 第 3 部分 中為應用程 序定義的函數相同。請注意,有一個新方法用於支持 Add new PhonebookEntry 功能。

清單 2. PhonebookDataProvider 定義所有方法並實現 IPhonebookDataProvider 接口

public  class PhonebookDataProvider implements IPhonebookDataProvider{
  private  IPhonebookDAO pbDao;

  public PhonebookDataProvider() {
  }

  public void setPbDao(IPhonebookDAO pbDao) {
    this.pbDao = pbDao;
  }

  public List getPhonebookEntries() throws Exception{
     return pbDao.getPhonebookEntries();
  }

  public PhonebookEntry  getPhonebookEntry(int entryID, int rowID) throws Exception{
    return  pbDao.getPhonebookEntry(entryID, rowID);
  }

  public int addEntry (PhonebookEntry pe) throws Exception{
    return pbDao.addEntry(pe);
   }
}

引入方法標記的方面

方法標記的方面將捕捉所有對被標記方法的調用 及從其返回的結果。我們將在這些聯結點處顯示一條消息。如在 AOP 的基礎知識 部分中的定義,有三類 建議:Before、After 和 Around。Spring AOP 有支持全部三類建議的接口。我們將定義三個類用於實現 這些接口並在每個接口中放置標記程序以查看運行情況。

Before 建議

MarkingBeforeAdvice 類用於為本 AOP 示例定義 Before 建議。它將實現 MethodBeforeAdvice 接口。下面是從該接口實現 before(...) 方法的代碼。

清單 3. 實現 Before 建議的示例

public class MarkingBeforeAdvice implements MethodBeforeAdvice 
{
  public void before(java.lang.reflect.Method method, Object[] obj, Object obj2)
throws Throwable {
    Calendar cal = Calendar.getInstance();
     System.out.println(cal.getTime() + " :::: PREPARING TO CALL "+method.getName() +"
of "+obj2.getClass().getName()+"");
  }

}

這個 Advice 類定義用於指定實現 before() 方法以啟用 Spring 運行時在達到適當的聯結點時通報建議。

必須讓 Spring 應用程序上下文識別到此建議,還要將此建議附加到應用程序的適當聯結點上。 清單 4 顯示了實現上述操作的配置。

清單 4. 向應用程序上下文中添加 Before 建議

<bean id="beforeTracer"
class="phonebook.aop.MarkingBeforeAdvice"/>

  <!-- Bean Definitions  for Advisors -->

  <!-- Before Marking Advisor -->
   <bean id="beforeMarkingAdvisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
     <property name="advice">
      <ref local="beforeTracer"/>
     </property>
    <property name="pattern">
       <value>.*</value>
    </property>
  </bean>

  <bean id="phonebook"
class="org.springframework.aop.framework.ProxyFactoryBean">
    <property  name="proxyInterfaces">
       <value>phonebook.dao.IPhonebookDataProvider</value>
     </property>
    <property name="target">
      <ref  local=" phonebookJdbcDataProvider"/>
    </property>
     <property name="interceptorNames">
      <list>
         <value>beforeMarkingAdvisor</value>
      </list>
     </property>
  </bean>

此處的第一個 Bean 定義用 Before 建議 接口的實現定義一個新 Bean。

第二個定義將定義 before 標記建議程序。它定義了切入點及必須 在每個切入點上執行的建議。可以使用正則表達式為應當應用建議的選定方法設定模式。我僅使用了 .* RE 將此應用到目標對象的所有方法中。

使用 ProxyFactoryBean 的最後一個 Bean 是起整合作用 的實際 Bean。ProxyFactory 在接口上運行,並且它將僅把此方面應用到實現在此屬性中定義的接口的類 中。目標用於指定方面應當圍繞的對象。

After 建議

After 建議的定義與上述類似;開始 先定義一個用於實現 AfterReturningAdvice 接口的類。afterReturning() 方法將在目標對象上的實際 方法執行完後在運行時被攔截。

可以在 src 目錄中查看類和定義。

Around 建議

添加 Around 建議的過程與上面說明的 Before 建議定義十分相似,只有一處重要區別。由於 Around 建 議在 Spring AOP 中是作為攔截程序被實現的,因此實現類將實現 MethodIntercepter 接口。

另 一個重要區別在於通過在 MethodInvocation 對象上調用 proceed() 方法會明顯延長執行流程。如果不 這樣做,則 Around 建議方面將不在目標對象上調用方法。這種設計為開發人員提供了定義實際方法被調 用後的前操作和後操作的能力。

清單 5 展示了 Around 建議類的定義。

清單 5. 實現 Around 建議的類

public class MarkingInterceptor implements MethodInterceptor  {
  public Object invoke(org.aopalliance.intercept.MethodInvocation  methodInvocation)
throws Throwable {

    Calendar cal =  Calendar.getInstance();
    System.out.println(cal.getTime() + " :::: NOW  INVOKING
"+methodInvocation.getMethod().getName()+".");

    Object  retVal = methodInvocation.proceed();

    cal = Calendar.getInstance();
    System.out.println(cal.getTime() + " :::: FINISHED INVOKING
"+methodInvocation.getMethod().getName()+".");

    return retVal;
   }
}

您可以看到此類與壓縮文件附帶的可部署的 .war 文件協作,也可以按照以下 說明構建和部署該文件。

構建、部署和運行

本教程附帶的源壓縮文件配有所有類、配置文 件和 Ant 構建文件(如果需要構建)。壓縮文件中還有一個配有全部所需內容的可部署的 .war 文件。 可以使用任何一種方法來獲取 phonebook.war 文件。

還必須確保 <WORKSPACE>/phonebook/lib 目錄中包含 readme.txt 文件中提及的所有 JAR 文件。請仔細閱讀 readme.txt 文件中的說明並確保將所有必需的文件都復制到 <WORKSPACE>/phonebook/lib 中。

注: 可以參考本系列教程的 第 2 部分 中的構建和打包說明。

使用 Geronimo 中的 Deploy New 工具部署 phonebook.war。如果一切運行正常,將在 Geronimo Web Console 上看到一條消 息,說明 Phonebook application deployed successfully。

現在,將浏覽器指向新頁面: http://localhost:8080/phonebook/home-aop.jsp。

如果一切都按預期運行,主頁應當如 圖 8 所示。

圖 8. 運行在應用服務器中的 home-aop.jsp

應當會在 Geronimo Console 上看到系統消息,說明正被執行的所有建議。

剛剛看過了在應用程序中運行的跟蹤方面 。現在來看看如何通過在應用程序上下文文件中添加幾個 Bean 輕松地聲明性地引入事務管理方面。

用幾個 Bean 添加事務

是的,這就是將事務方面插入應用程序所需完成的全部工作。請參 閱 清單 6 中的這些 Bean。

清單 6. 事務管理 Bean

<!-- Bean Definitions  required for Transactional Support -->

  <bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
     <property name="dataSource" ref="pbJdbcDataSource"/>
  </bean>

  <bean id="phonebookTxn"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
>
    <property name="transactionManager" ref="txManager"/>
     <property 
name="proxyInterfaces"><value>phonebook.dao.IPhonebookDataProvider</ 
value></property>
    <property name="target"  ref="phonebookJdbcDataProvider"/>
    <property  name="transactionAttributes">
      <props>
         <prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>
       </props>
    </property>
  </bean>

第一個 Bean 用於定義管理事務時必須使用的事務管理程序。由於需要包裝 JDBC 事務,因此使用 Spring JDBC 模塊中的 TransactionManager 實現。它配有應用建議所需的方法攔截程序。

在本教程的先前部 分中講解過 TransactionProxyFactoryBean。現在是時候來查看一下它是如何實現事務所需的核心功能的 。並且如您所見,您可以向它插入任何事務管理程序並使其相互協作。需要定義一個目標對象,在這個目 標對象上事務應該被應用到目標屬性內。將使用在 第 3 部分 中定義的 phonebookJdbcDataProvider Bean 實現此操作。在那裡還可以學到定義此 Bean 和其他 Bean 向 Derby 數據庫讀取和寫入數據。

最後而且也是最重要的一步,定義 transactionAttributes。事務屬性包含需要使用哪些事務語 法的定義。此處就是 把事務應用到以 add 為開頭的所有方法中。PROPAGATION_REQUIRED 表示支持當前 的事務或創建一個新事務(如果沒有)。那一行中的最後一個條件告訴事務管理程序在出現異常時回滾事 務。減號表示回滾;如果在出現異常時仍要提交,則使用加號(+)。

這就是將事務引入應用程序所 需完成的全部工作。

構建並運行

全部完畢。運行 Ant 來構建並創建 WAR 文件。使用 Geronimo 中的 Deploy New 工具部署該文件。

讓浏覽器指向新頁面: http://localhost:8080/phonebook/home-aop.jsp。

將獲得同樣一個主頁,但這一次它是圍繞事 務的。應當親自嘗試添加並查看新條目。下面是一些用於測試事務管理程序的提示:

在 Add New Entry 頁面中添加所有字段;應當會看到所有信息都返回到主頁列表中。

不輸入名字或姓氏。將 會看到一條錯誤消息,並且在後端,事務會被回滾。可以通過查看主頁或數據表本身加以驗證。

最後也是最重要的一個測試是添加名字和姓氏並將其他所有字段留空。將會再次看到錯誤消息,事務也將 會被回滾。但如果還記得數據庫表定義和 AddEntry() 方法的 SQL 語句,就可以使用它們把數據插入第 一張表中 —— FirstName 和 LastName,然後把其余數據添加到第二張表中。有兩次插入操 作,因此如果在第二次插入時出現異常,事務管理程序將回滾最後一次提交的 SQL 語句。

至此 AOP 就全部介紹完了。完成了向應用程序中定義並添加兩個方面,現在將要添加 SWF。

Spring Web Flow

SWF 系統允許捕捉 UI 流程作為獨立模塊。這些模塊可在各種系統中重用。這裡將改用 SWF 來定義應用程序的導航流程。

在 SWF 中,每個流程都是一個有限狀態機 (FSM),其中包含狀 態和轉換。狀態表示執行一些動作或顯示給用戶以供用戶輸入的視圖。開始先定義 phonebookFlow.xml 文件。此文件將包含流程定義。

注:在流程定義中將不定義動作;那是高級主題。

然後將 對 JSP 表單做一些小改動,並查看其運行情況。

添加 SWF

現在可以將靜態流程和硬編碼 流程改為使用 SWF 聲明性地定義。可以通過三個步驟來實現:

在 XML 文件中定義應用程序的 Web 流程。

定義 XMLFlowFactory Bean 在 ApplicationContext 中訪問此流程。

執行此 流程。

第一步是在 XML 文件中定義流程。清單 7 顯示了用於本應用程序的這一流程。

清 單 7. PhonebookFlow.xml 為應用程序定義流程

<?xml version="1.0"  encoding="UTF-8"?>
<!DOCTYPE flow PUBLIC "-//SPRING//DTD WEBFLOW 1.0//EN"
    "http://www.springframework.org/dtd/spring-webflow-1.0.dtd">

<flow start-state="showPhonebook">

  <!-No Action Processing  plugged in so far. Just getting the flow in place first
-->

   <view-state id="showPhonebook" view="home-dao">
    <transition  on="goToAddEntry" to="addEntry">
    </transition>
  </view- state>

  <view-state id="addEntry" view="addentry">
     <transition on="goToHome"
to="showPhonebook"></transition>
     <transition on="saveEntry" to="addEntry"></transition>
  </view- state>
</flow>

此配置文件是不言自明的。此 XML 中的頂部條目用於為 應用程序定義啟動狀態。然後定義 showPhonebook 狀態的視圖狀態,然後再去定義 addEntry 狀態。視 圖屬性定義用於保留特殊視圖定義的 JSP。

流程部署

在 清單 7 中,看到了定義流程是多 麼容易。現在來看一看如何在特殊環境(例如 Spring MVC)內部署該流程(參見 清單 8)。

清 單 8. 部署此流程所需的配置

<bean id="flowRegistry"
class="org.springframework.webflow.registry.XmlFlowRegistryFactoryBean">
     <property name="flowLocations" value="/WEB-INF/phonebookFlow.xml"/>
   </bean>

  <!-- Creates, saves, and restores managed flow  executions -->
      <bean id="repositoryFactory"
class="org.springframework.webflow.execution.repository.continuation.ContinuationFlow
ExecutionRepositoryFactory">
        <constructor-arg  ref="flowRegistry"/>
      </bean>

      <!--  Launches new flow executions and resumes existing executions. -->
       <bean id="flowExecutor"
class="org.springframework.webflow.executor.FlowExecutorImpl">
             <constructor-arg ref="repositoryFactory"/>
      </bean>

      <bean name="phonebookFlowController"
class="org.springframework.webflow.executor.mvc.FlowController">
             <property name="flowExecutor" ref="flowExecutor"/>
             <property name="cacheSeconds" value="5"/>
       </bean>

此處有兩個主要的 Bean:第一個 Bean,用於定義流程定義文件的位置; 最後一個 Bean,用於將該 Bean 提供給 FlowController 實現。MVC FlowController 配有在執行時將此 配置轉換為流程的所有邏輯。

在 JSP 頁面中做一些小改動

在 addEntry.jsp 頁面的以下 部分中最重要的部分是 _flowExecutionKey 輸入參數。此鍵是由 SWF 生成的,並且將被作為一個隱藏參 數傳入參與此流程的每個頁面。流程都是有狀態的。結果,參與流程的視圖必須將 _flowExecutionKey 參數提交回服務器以識別客戶機正在參與的流程。此外,視圖必須將一張可解析的 _eventId 參數表提交 回服務器以通報在按下按鈕時發生的事件 —— 例如,當 Submit 按鈕被按下時的提交事件。

清單 9 顯示了 addEntry.jsp 頁面中的這些更改。

清單 9. JSP 頁面中的更改

...
<script type="text/javascript">
 function doSave()
 {
  document.myForm.pageAction.value="ADD";
   document.myForm._eventide.value="saveEntry";
  document.myForm.submit();
 }

 function goHome()
 {
   document.myForm. _  eventide.value="goToHome";
  document.myForm.submit();
 }

...
...

    <input type=hidden name=pageAction value=""/>
     <input type="hidden" name="_flowExecutionKey"
value="${flowExecutionKey}">
<input type="hidden" name="_eventId" value=""/>
... 

需要對 home-dao.jsp 頁面做類似更改,將使用該頁面作為流程示例的主頁。這十分簡單。請查看 src 中的 JSP 文件。

構建並運行

就這些!已經全部完成了。運行 Ant 來構建並創建 WAR 文件。使用 Geronimo 中的 Deploy New 工具部署該文件。

需要傳入流程定義名稱,以便 SWF 可以執行該流 程。使浏覽器指向此 URL:http://localhost:8080/phonebook/phonebook.htm?_flowId=phonebookFlow 。

當單擊此 URL 時,SWF 將創建新流程,還將管理新流程!

當部署源文件附帶的 .war 文件並指向上述 URL 時,實際上就已經查看到了本教程中討論的所有技術的運行情況。

至此已實 現了本教程設定的所有目標。

Spring 的優點

本教程中涉及的主要技術包括 Spring AOP、 聲明性事務管理和 SWF。每一項技術都會在 Spring 框架中添加已經備受矚目的模塊集。

下面列 出了使用 Spring 聲明性事務管理與使用諸如 Enterprise JavaBeans Container-Managed Transactions (EJB CMT) 這類工具相比的優勢:

Spring 的事務管理不依賴於任何環境,就好像 EJB CMT 之於 Java 事務 API (JTA) 一樣。它可以工作於 JDBC、Java Data Objects (JDO)、Hibernate 或其他有非常 少的配置更改的事務。

Spring 的事務管理可以應用到所有傳統 Jave 對象 (POJO),而不僅僅是 應用到諸如 EJB 之類的特殊類。

Spring 提供了簡單的聲明回滾規則,這些規則在其他環境中很 難實現。

可以在 Spring 中將 AOP 添加到事務頂部。

如您所見,SWF 是另一個功能強大 的 Spring 模塊。使用 SWF 與使用其他工具相比的優勢在於:

應用程序的導航流程是在 .xml 文 件中定義的,它清晰可見並且易於理解。

使用 SWF 定義的流程可在其他場景中重用。

Web Flow 的使用合同定義得非常好。它的生命周期清晰、可觀察,並被自動管理。簡單地說,系統將負責管 理復雜性,因此它十分易於使用。

結束語

在本教程中,您了解了 Spring AOP 並嘗試了 Spring AOP 所支持的聲明性事務管理。AOP 很難理解和實現,但是通過方法跟蹤的方面的演示,您可以 看到 Spring 框架簡化了使用 AOP 的過程。本教程還向您介紹了功能強大的新工具 SWF。

您看到 了 Geronimo Web Console 如何使創建及管理數據庫變得較為輕松,使用部署工具又如何使部署應用程序 變得十分簡單。在執行所有這些操作期間,您甚至一次都不需要重新啟動服務器。

在第 5 部分中 ,將探討最重要的 Spring 模塊:Spring MVC。在先前的教程中零零碎碎地看到了此模塊的運行,而在第 5 部分中您將進一步深入了解其特性和功能。

您將接觸到 Spring MVC 提供的各種控制程序和處 理程序。您的應用程序將被擴展以便添加更多功能,包括修改和刪除電話本條目。敬請關注!

下 載

描述 名字 大小 下載方法 第 4 部分 的源代碼 geronimo.spring4.source.zip 119KB HTTP 第 4 部分的 WAR 文件 geronimo.spring4.war.zip 4150KB HTTP
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved