首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Apache Geronimo 與 Spring 框架實戰(四):Spring AOP 與 Web Flow 深度整合

     編輯:Java 相關知識

本系列教程共六部分,此為第四篇,重點介紹 Spring AOP(面向切面編程)模組如何簡化切面導向開發,以及 Spring Web Flow (SWF) 如何以 XML 宣告式方式定義 Web 應用流程。您將看到如何利用 Spring AOP 實現聲明式事務管理,並體驗 Apache Geronimo 管理主控台讓資料庫建立與管理更輕鬆——全程無需重啟伺服器。

教學目標與適用對象

本教程適合想深入了解 Spring 框架、並掌握在 Apache Geronimo 應用伺服器上發揮其威力的 Java EE 開發人員。我們將繼續打造個人電話簿應用程式,功能涵蓋:顯示電話簿、查看條目詳情、新增/編輯/刪除條目、擴充欄位(如主 Email)等。

系列回顧

  • 第一部分:Spring 架構七大模組與 Geronimo 整合基礎
  • 第二部分:建立首個 Spring 骨架應用並部署至 Geronimo
  • 第三部分:整合 Spring JDBC、DAO 與 iBATIS ORM,實現動態資料存取
  • 第四部分(本篇):Spring AOP 與 Spring Web Flow 實戰
  • 第五部分:Spring MVC 深度解析
  • 第六部分:Spring MVC 視圖技術(JSP、Velocity、Tiles、PDF匯出)

核心內容:Spring AOP 基礎與實作

AOP 核心概念速覽

AOP 將橫切關注點(如日誌、事務、安全)從業務邏輯中分離。核心術語包括:

  • 切面:封裝橫切行為的模組(類似類)
  • 連接點:程式執行中可插入切面的邏輯點(Spring 僅支援方法呼叫)
  • 通知:在連接點執行的動作(Before/After/Around/Throws)
  • 切入點:定義通知觸發條件的連接點集合(支援正則表達式)
  • 目標物件:被通知的物件
  • AOP 代理:由框架建立實現切面邏輯的代理(JDK 動態代理或 CGLIB)
  • 織入:將切面套用至目標物件的過程(Spring 在執行期織入)
Spring AOP 概念架構圖
圖 1:Spring AOP 中的 AOP 概念

Spring AOP 實作三種通知類型

以電話簿應用為例,我們定義「方法標記」切面來追蹤方法呼叫流程:

前置通知

實作 MethodBeforeAdvice 介面,在方法執行前輸出追蹤訊息:

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

後置通知

實作 AfterReturningAdvice,方法正常返回後執行:

public class MarkingAfterAdvice implements AfterReturningAdvice {
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        Calendar cal = Calendar.getInstance();
        System.out.println(cal.getTime() + " :::: FINISHED CALLING " + method.getName());
    }
}

環繞通知

最強大也最常用,實作 MethodInterceptor,可完全控制執行流程:

public class MarkingInterceptor implements MethodInterceptor {
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Calendar cal = Calendar.getInstance();
        System.out.println(cal.getTime() + " :::: NOW INVOKING " + invocation.getMethod().getName());
        
        Object retVal = invocation.proceed(); // 必須顯式呼叫才會執行目標方法
        
        cal = Calendar.getInstance();
        System.out.println(cal.getTime() + " :::: FINISHED INVOKING " + invocation.getMethod().getName());
        return retVal;
    }
}
Before Advice 事件序列圖
圖 2:定義 Before Advice 後的事件序列
After Advice 事件序列圖
圖 3:After Advice 的事件序列
Around Advice 事件執行圖
圖 4:Around Advice 的事件執行

XML 組態:將切面織入應用

在 ApplicationContext.xml 中定義 Bean 與代理:

<!-- 定義通知 Bean -->
<bean id="beforeTracer" class="phonebook.aop.MarkingBeforeAdvice"/>

<!-- 定義切入點與通知的關聯 -->
<bean id="beforeMarkingAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice"><ref local="beforeTracer"/></property>
    <property name="pattern"><value>.*</value></property> <!-- 套用至所有方法 -->
</bean>

<!-- ProxyFactoryBean 整合 -->
<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>

聲明式事務管理:零程式碼實現 ACID

Spring 利用 AOP 內部實現事務,開發者只需在 XML 宣告:

<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>

PROPAGATION_REQUIRED 表示支援現有事務或建立新事務;-Exception 表示遇到例外回滾。測試時嘗試新增條目時留空必填欄位,即可觀察事務自動回滾。

Spring Web Flow:宣告式定義 Web 流程

為什麼需要 SWF?

隨著應用複雜度增加,頁面導航邏輯分散在各處難以維護。SWF 以有限狀態機(FSM)建模流程,在 XML 中定義狀態與轉換,支援跨環境重用(Struts、JSF、Portlet 等)。

流程定義範例

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

整合 SWF 至 Spring MVC

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

<bean id="repositoryFactory" class="org.springframework.webflow.execution.repository.continuation.ContinuationFlowExecutionRepositoryFactory">
    <constructor-arg ref="flowRegistry"/>
</bean>

<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>

JSP 頁面配合流程執行

關鍵在於隱藏欄位 _flowExecutionKey 與 _eventId:

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

<script>
function doSave() {
    document.myForm._eventId.value = "saveEntry";
    document.myForm.submit();
}
function goHome() {
    document.myForm._eventId.value = "goToHome";
    document.myForm.submit();
}
</script>

建構、部署與驗證

  1. 確認 <WORKSPACE>/phonebook/lib 包含所有必要 JAR(參考 readme.txt)
  2. 執行 Ant 建構 WAR 檔
  3. 使用 Geronimo 管理主控台 Deploy New 部署
  4. 瀏覽 https://localhost:8080/phonebook/home-aop.jsp 測試 AOP 追蹤
  5. 瀏覽 https://localhost:8080/phonebook/phonebook.htm?_flowId=phonebookFlow 體驗 SWF 流程
home-aop.jsp 運行畫面
圖 5:運行在應用伺服器中的 home-aop.jsp

Spring AOP + SWF 的優勢總結

技術核心優勢
聲明式事務 不依賴 EJB 容器、可套用至 POJO、簡單的回滾規則、可疊加自訂 AOP
Spring Web Flow 流程定義外部化、可重用、生命週期清晰受管、解決 MVC 中 Controller 複雜度

下一步預告

第五部分將深入 Spring MVC,探討各類 Controller 與 Handler,並擴充電話簿的修改、刪除功能。敬請期待!

下載資源

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved