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

Seam 框架深度解析:為 JSF 量身打造的無縫應用框架(上)

     編輯:Java 程式設計入門

JavaServer Faces (JSF) 作為 Java EE 官方 Web UI 標準,提供了基於組件的事件驅動開發模型,但規范明確宣稱:JSF 不是完整的 Web 應用框架,缺乏會話狀態管理、RESTful URL、書簽支持、異常處理、Ajax 整合等關鍵能力。JBoss Seam(以下簡稱 Seam)應運而生,作為 JSF 的「最佳搭檔」,通過擴展 JSF 生命周期、引入雙向注入、會話上下文、頁面動作、工廠模式、異常處理、Ajax Remoting 等機制,將 JSF 從「組件庫」提升為「企業級應用框架」。本系列首篇將系統剖析 Seam 核心架構、配置啟動、組件模型、與 Spring/EJB3 的集成策略。

一、為什麼選擇 Seam?

JSF 痛點Seam 解決方案
依賴 HTTP Session 傳遞多頁數據,導致內存洩漏、多標簽頁衝突引入 Conversation Scope(會話上下文),綁定瀏覽器標簽頁,自動生命周期管理
無原生書簽/RESTful URL 支持,頁面導航依賴 POST-Redirect-GET頁面動作 + s:link/s:button 實現 GET 請求導航,URL 可收藏、可分享
異常處理僅依賴 Servlet 容器 error-page,無法回滾事務、無法訪問 FacesContext註解/配置驅動異常處理,支援 HTTP 狀態碼、重定向、會話終止、用戶友好提示
大量 XML 配置(faces-config.xml, pages.xml)Java 5 註解(@Name, @In, @Out, @Factory, @Observer 等)替代 XML,約定優於配置
Ajax 整合困難,需自定義 PhaseListener/Renderer@WebRemote + Ajax4JSF 實現 JavaScript 直接調用服務端組件方法,支援局部渲染

二、Seam 組件模型:POJO 為主,EJB3 可選

Seam 組件本質是帶有 @Name 註解的 POJO,容器負責實例化、生命周期、上下文綁定、依賴注入。**不強制要求 EJB3 容器**,可在 Tomcat/Jetty 等 Servlet 容器中運行。若需 EJB3 服務(事務、安全、遠程調用),可無縫集成。

2.1 核心註解速查

註解作用示例
@Name("userManager")聲明組件名稱,綁定到上下文變量 #{userManager}@Name("userManager") public class UserManager {}
@Scope(ScopeType.CONVERSATION)指定作用域(默認 CONVERSATION)@Scope(CONVERSATION) @Name("cart") public class ShoppingCart {}
@In / @Out雙向注入:@In 注入上下文變量,@Out 注出到上下文@In User user; @Out Order order;
@Factory("users")工廠方法:首次請求 #{users} 時調用,結果緩存至上下文@Factory("users") public List loadUsers() { return dao.findAll(); }
@DataModel / @DataModelSelection綁定數據表格選中行,自動注入/注出@DataModel List users; @DataModelSelection @Out User selectedUser;
@Observer("userSaved")事件觀察者:接收 Events.instance().raiseEvent("userSaved")@Observer("userSaved") public void onUserSaved() { log.info("User saved"); }
@WebRemote暴露方法供 JavaScript 遠程調用(Ajax Remoting)@WebRemote public String validateUsername(String name) { return dao.exists(name) ? "taken" : "ok"; }

2.2 典型 Seam POJO 組件

@Name("addressManager")
@Scope(ScopeType.CONVERSATION)
public class AddressManagerBean {
    @DataModel
    private List
addresses; @DataModelSelection @Out(required = false) private Address selectedAddress; @Factory("addresses") public void loadAddresses() { this.addresses = addressService.findAll(); } public String showDetail() { return "/address.xhtml"; // 導航結果 } public String list() { return "/addresses.xhtml"; } }

三、最小化啟動配置(4 步走)

  1. 添加依賴 JAR:jboss-seam.jar, jboss-seam-ui.jar, javassist.jar, hibernate-validator.jar, javax.persistence-api.jar 等。
  2. web.xml 註冊 Seam Listener:
    <listener>
        <listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
    </listener>
  3. faces-config.xml 註冊 PhaseListener:
    <lifecycle>
        <phase-listener>org.jboss.seam.jsf.SeamPhaseListener</phase-listener>
    </lifecycle>
  4. 類路徑根目錄放置空 seam.properties:觸發組件掃描,優化啟動性能。

四、Seam 與 Spring 集成:最佳雙容器協作

許多項目已投入 Spring 管理服務層/DAO,Seam 提供無縫橋接:

  1. 確保已配置 Spring-JSF 集成(DelegatingVariableResolver 或 SpringBeanFacesELResolver)。
  2. 在 Seam 組件中使用 @In("#{springBeanName}") 注入 Spring Bean。
@Name("orderManager")
public class OrderManagerBean {
    @In("#{orderService}") // 引用 Spring 容器中名為 orderService 的 Bean
    private OrderService orderService;

    @In("#{userDao}")
    private UserDao userDao; // 甚至可直接注入 DAO(不推薦,應注入 Service)
}

未來版本將提供 Spring 專用命名空間簡化配置。此模式實現:Seam 管理 Web 狀態與導航,Spring 管理業務邏輯與數據訪問,部署目標僅需 Servlet 容器。

五、JSF 與 Seam 生命周期融合

Seam 通過 SeamPhaseListener 植入 JSF 六大階段:

  1. Restore View:恢復組件樹,Seam 恢復 Conversation 上下文。
  2. Apply Request Values:Seam 執行頁面動作參數注入。
  3. Process Validations:Seam 協調驗證邏輯。
  4. Update Model Values:雙向注入(@In/@Out)同步模型。
  5. Invoke Application:執行動作方法,Seam 管理事務邊界。
  6. Render Response:工廠方法(@Factory)按需準備數據,Ajax4JSF 處理局部渲染。

關鍵增強點:頁面動作(在 Render Response 前執行)、工廠數據懶加載、Conversation 狀態跨請求保持、異常捕獲與轉換、Ajax Remoting 方法暴露。

六、頁面動作:實現 RESTful 導航的核心

在 WEB-INF/pages.xml 或 viewId.page.xml 中聲明:

<page view-id="/product/detail.xhtml">
    <action execute="#{productManager.loadProduct(productId)}" />
    <param name="productId" value="#{productManager.productId}" />
    <navigation from-action="#{productManager.loadProduct}">
        <rule if-outcome="notFound">
            <redirect view-id="/error/404.xhtml" />
        </rule>
    </navigation>
</page>

優勢:

  • 請求參數自動綁定到模型(#{productManager.productId})。
  • 動作方法可返回導航結果(字符串 Outcome),支援重定向/轉發。
  • Seam 組件標籤 <s:link>, <s:button> 生成 GET 請求鏈接,天然支援書簽、SEO、瀏覽器歷史記錄。
  • URL 可映射為 RESTful 風格:/product/123 → /product/detail.xhtml?productId=123。

七、工廠組件:按需準備視圖數據

解決 JSF「Getter 多次調用導致重複查詢」痛點。@Factory("addresses") 標註的方法在 #{addresses} 首次被 EL 解析時執行一次,結果存入當前作用域(默認 Conversation),後續直接返回緩存對象。配合 Conversation 作用域,實現**請求級/會話級數據緩存**,極大減輕數據庫壓力。

八、總結與展望

Seam 以極低的接入成本(4 個 JAR + 3 個配置項 + 1 個空文件),為 JSF 注入了企業級應用框架靈魂:**有狀態組件模型、雙向注入、Conversation 上下文、頁面動作、工廠模式、優雅異常處理、Ajax Remoting**。下一篇將深入剖析 Conversation Scope 實現原理、異常處理最佳實踐、Ajax4JSF 整合細節、生產部署調優**,敬請期待。

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