原貼網址:
http://www.jdon.com/jivejdon/thread/34551.html
最近注意了一下Seam文檔,牛人Gavin King的觀點貌似好多都曾出現在jdon,在jdon上混得久的人也許早就注意到了,下面貼文檔的一部分:
有狀態Session Bean不僅可以在bean的多次調用之間保持狀態,而且在多次請求之間也可以保持狀態。 不由數據庫保存的狀態通常應該由有狀態Session Bean保持。這是Seam和其他web框架之間的一個顯著的不同點。 其他框架把當前會話的信息直接保存在 HttpSession 中,而在Seam中你應該把它們保存在有狀態Session Bean的實例中,該實例被綁定到會話上下文。這可以讓Seam來替你管理狀態的生命周期,并且保證在多個不同的并發會話中沒有狀態沖突。
Seam是從Hibernate團隊試圖生成典型的無狀態Java應用架構的挫折中成長起來的。 上一代Java應用程序的無狀態特性讓Hibernate團隊飽受挫折,Seam吸取了他們的經驗。 Seam的 狀態管理架構最早是用來解決持久化沖突相關問題的,特別是 樂觀事務處理 相關的問題。可擴展的在線應用經常使用樂觀事務。 一個原子(database/JTA)級的事務不應該跨用戶交互,除非系統設計時就是只支撐很少量的并發客戶端。 但幾乎所有涉及到的工作都是先將數據展現給用戶,沒多久后更新這個數據。所以Hibernate是依據支持一種跨樂觀事務的持久化上下文的思想設計的。
不幸的是這個先于Seam和EJB3.0出現的所謂“無狀態”架構并不對樂觀事務進行支持。而相反,這些架構提供對于原子事務級的持久化上下文的支持。 這當然給用戶帶來了很多麻煩,這也是用戶抱怨排名第一的Hibernate的 LazyInitializationException 問題的原因。 我們需要的是在應用層構建對于樂觀事務的支持。
EJB3.0認識到了此問題,并且也引入了有狀態組件(有狀態會話bean)的思想,它使用一個 擴展持久化上下文來跟蹤組件的生命周期。 這是該問題的部分解決方案(對它自身而言也是一個有用的構想),然而還有兩個問題:
有狀態會話bean的生命周期必須在Web層通過代碼手動管理(這是個麻煩的問題,而且實踐起來比聽上去更復雜)。
在同一個樂觀事務的不同有狀態組件間,傳播持久化上下文是可行的,但很困難。
Seam通過提供對話(Conversation)和對話期間的有狀態Session Bean組件來解決第一個問題(大多數會話實際上在數據層支持樂觀事務)。 這對于很多不需要傳遞持久化上下文的簡單應用(比如Seam的訂閱演示程序)已經足夠了。 對于更復雜的在每一個對話中的有很多松耦合組件的應用來說,組件間傳播持久化上下文就成為一個重要的問題了。 所以Seam擴展了EJB 3.0的持久化上下文管理模型,以此來提供對話作用域的擴展持久化上下文。
數據庫成為了大多數企業應用的主要瓶頸,也成為了運行環境中最不具伸縮性的層。PHP/Ruby的用戶會說什么都不共享(share nothing)的架構照樣具有很好的伸縮性。從表面上看也許是對的,可惜我不知道是否存在這樣的多用戶應用,其實現是能夠在集群的 不同結點間不共享資源。這些傻瓜真正想的是“除了數據庫以外什么都不共享(Share nothing except for the database)”的架構。當然,共享數據庫是多用戶應用伸縮性的主要問題——因此聲稱這樣的架構具有高伸縮性是荒謬的,你可要知道它們花費了這些人的 大部分時間。
通常,幾乎所有通過共享數據庫做的事情并不值得這樣去做。
這就是緩存(Cache)產生的原因。嗯,當然并不只是一個緩存。一個設計良好的Seam應用將具有豐富的多層緩存策略,這也影響著應用的每一層:
當然,數據庫有它自己的緩存,這是超級重要的,但是它不能像應用層的緩存一樣具有伸縮性。
對從數據庫提取出的數據,你的ORM解決方案(Hibernate,或者別的JPA實現)具有兩級緩存。這是一種很強大的能力,但是經常被誤用。在一個集群環境里,保持緩存中的數據在整個集群中具有事務一致性,并且和數據庫一致,其代價是相當昂貴的。這對于共享在多個用戶間,且很少被更新的數據最有意義。在傳統的無狀態架構里,人們經常使用二級緩存來保存會話狀態。這種做法總是糟糕的,在Seam中更是大錯特錯的。
Seam會話上下文是會話狀態的緩存。存儲于會話上下文中的組件可以保持并緩存與當前用戶交互相關的狀態。
特別的,Seam管理的持久化上下文(或者一個擴展受管EJB容器持久化上下文,它與會話范圍的無狀態會話Bean相關)成為了當前會話中數據的緩存。這種緩存趨向于擁有一個相當高的命中率!Seam優化了集群環境中受管Seam持久化上下文的復制,也不需要保證數據庫事務的一致性(樂觀鎖已足夠),因此你不必擔心這種緩存的性能問題,除非你把成千上萬個對象讀取到一個單獨的持久化上下文中。
應用可以在Seam應用上下文中緩存非事務性狀態。相應的,保存在應用上下文中的狀態不能被集群中其它結點訪問。
應用通過Seam的 pojoCache 組件可以緩存事務性狀態,這個組件把JBossCache集成到了Seam環境中。如果你在集群模式下運行了JBossCache,那么這個狀態是可以被別的結點訪問的。
最后,Seam讓你能夠緩存生成的JSF頁面的部分內容(rendered fragments)。與ORM的二級緩存不一樣的是,當數據發生變化時,這種緩存不能自動的失效,因此你需要寫應用代碼來使它顯式的失效,或者設置適當的過期策略。
如要獲得更多關于二級緩存的信息,你可以參考你的ORM解決方案的文檔,因為這是個極為復雜的話題。在這節中我們會直接討論通過 pojoCache 組件使用JBossCache,或者通過 <s:cache>控制充當頁片段(page fragment)緩存。
EJB 會話Bean有聲明式事務管理功能。當Bean被調用時,EJB容器能夠透明地開始一個事務,在調用結束時關閉此事務。 如果我們寫了一個作為JSF動作監聽器的會話Bean方法,我們就可以在一個事務內處理所有與此action相關的工作,并且當我們完成此動作處理時事務 必須被提交或回滾。 這是一個很棒的功能,在很多Seam應用程序中這是必需的。
但是,此方法還是有問題。Seam應用可能無法在對會話Bean的一次方法調用請求中完成所有的數據訪問。
此請求可能由幾個松耦合組件處理,Web層獨立地調用每一個組件。在Seam中,Web層的一個請求對EJB組件發起幾次甚至多次調用的現象是很常見的。
視圖渲染可能需要延遲關聯獲取(lazy fetching of associations)。
每個請求的事務量越多,當我們的應用處理大量并發請求時越可能碰到原子和隔離問題。當然,所有的寫操作要在一個事務中執行。
Hibernate用戶開發了 "Open Session in View" 模式來解決該問題。 在Hibernate社區,"Open Session in View"曾經非常重要,這是因為像Spring這樣的框架使用了事務作用域持久化上下文。 所以當未獲得的關聯被訪問時渲染視圖將引起 LazyInitializationException 異常。
這 個模式通常作為一個跨越整個請求的事務來實現。 此實現方式會有幾個問題,其中最嚴重的是只有我們提交了事務才能確認它成功完成——但在"Open Session in View"的事務提交時,視圖已經完全渲染了,甚至渲染好的應答可能已經刷新到客戶端。我們怎樣才能通知用戶他們的事務已失敗呢?
Seam在解決"Open Session in View"問題時,也解決了事務隔離和關聯獲取問題。該方案有有兩個部分:
使用使用已擴展持久化上下文,可以覆蓋一個會話作用域而不是單個事務作用域。
每次請求使用兩個事務;第一個從更新模型值的起始階段到應用程序調用結束;第二個跨越渲染響應階段。
很多應用服務器的 HttpSession 集群實 現都有問題,對綁定到Session的可變對象狀態的改變只有在明確調用 setAttribute() 的時候才會被復制。 這是Bug的一個源頭,這些Bug難以在開發階段有效找出,因為它們只會在應用服務器失效切換的時候才會被發現。 而且,實際的復制信息包含了綁定到Session的所有序列化對象圖,這是低效的。
當然,EJB 有狀態Session Bean必須進行自動dirty checking,并進行可變狀態的復制,并且EJB 容器也應該引入優化,例如屬性級別的復制。 但不幸的是,并非所有的Seam用戶都有這么好的運氣,他們的環境可能并不支持EJB 3.0。 因此,對于Session和Conversation范圍內的JavaBean和Entity Bean組件,在Web容器的Session集群之上,Seam提供了額外的集群安全的狀態管理層。
|
有狀態Session Bean不僅可以在bean的多次調用之間保持狀態,而且在多次請求之間也可以保持狀態。 不由數據庫保存的狀態通常應該由有狀態Session Bean保持。這是Seam和其他web框架之間的一個顯著的不同點。 其他框架把當前會話的信息直接保存在 HttpSession 中,而在Seam中你應該把它們保存在有狀態Session Bean的實例中,該實例被綁定到會話上下文。這可以讓Seam來替你管理狀態的生命周期,并且保證在多個不同的并發會話中沒有狀態沖突。
Seam是從Hibernate團隊試圖生成典型的無狀態Java應用架構的挫折中成長起來的。 上一代Java應用程序的無狀態特性讓Hibernate團隊飽受挫折,Seam吸取了他們的經驗。 Seam的 狀態管理架構最早是用來解決持久化沖突相關問題的,特別是 樂觀事務處理 相關的問題。可擴展的在線應用經常使用樂觀事務。 一個原子(database/JTA)級的事務不應該跨用戶交互,除非系統設計時就是只支撐很少量的并發客戶端。 但幾乎所有涉及到的工作都是先將數據展現給用戶,沒多久后更新這個數據。所以Hibernate是依據支持一種跨樂觀事務的持久化上下文的思想設計的。
不幸的是這個先于Seam和EJB3.0出現的所謂“無狀態”架構并不對樂觀事務進行支持。而相反,這些架構提供對于原子事務級的持久化上下文的支持。 這當然給用戶帶來了很多麻煩,這也是用戶抱怨排名第一的Hibernate的 LazyInitializationException 問題的原因。 我們需要的是在應用層構建對于樂觀事務的支持。
EJB3.0認識到了此問題,并且也引入了有狀態組件(有狀態會話bean)的思想,它使用一個 擴展持久化上下文來跟蹤組件的生命周期。 這是該問題的部分解決方案(對它自身而言也是一個有用的構想),然而還有兩個問題:
有狀態會話bean的生命周期必須在Web層通過代碼手動管理(這是個麻煩的問題,而且實踐起來比聽上去更復雜)。
在同一個樂觀事務的不同有狀態組件間,傳播持久化上下文是可行的,但很困難。
Seam通過提供對話(Conversation)和對話期間的有狀態Session Bean組件來解決第一個問題(大多數會話實際上在數據層支持樂觀事務)。 這對于很多不需要傳遞持久化上下文的簡單應用(比如Seam的訂閱演示程序)已經足夠了。 對于更復雜的在每一個對話中的有很多松耦合組件的應用來說,組件間傳播持久化上下文就成為一個重要的問題了。 所以Seam擴展了EJB 3.0的持久化上下文管理模型,以此來提供對話作用域的擴展持久化上下文。
數據庫成為了大多數企業應用的主要瓶頸,也成為了運行環境中最不具伸縮性的層。PHP/Ruby的用戶會說什么都不共享(share nothing)的架構照樣具有很好的伸縮性。從表面上看也許是對的,可惜我不知道是否存在這樣的多用戶應用,其實現是能夠在集群的 不同結點間不共享資源。這些傻瓜真正想的是“除了數據庫以外什么都不共享(Share nothing except for the database)”的架構。當然,共享數據庫是多用戶應用伸縮性的主要問題——因此聲稱這樣的架構具有高伸縮性是荒謬的,你可要知道它們花費了這些人的 大部分時間。
通常,幾乎所有通過共享數據庫做的事情并不值得這樣去做。
這就是緩存(Cache)產生的原因。嗯,當然并不只是一個緩存。一個設計良好的Seam應用將具有豐富的多層緩存策略,這也影響著應用的每一層:
當然,數據庫有它自己的緩存,這是超級重要的,但是它不能像應用層的緩存一樣具有伸縮性。
對從數據庫提取出的數據,你的ORM解決方案(Hibernate,或者別的JPA實現)具有兩級緩存。這是一種很強大的能力,但是經常被誤用。在一個集群環境里,保持緩存中的數據在整個集群中具有事務一致性,并且和數據庫一致,其代價是相當昂貴的。這對于共享在多個用戶間,且很少被更新的數據最有意義。在傳統的無狀態架構里,人們經常使用二級緩存來保存會話狀態。這種做法總是糟糕的,在Seam中更是大錯特錯的。
Seam會話上下文是會話狀態的緩存。存儲于會話上下文中的組件可以保持并緩存與當前用戶交互相關的狀態。
特別的,Seam管理的持久化上下文(或者一個擴展受管EJB容器持久化上下文,它與會話范圍的無狀態會話Bean相關)成為了當前會話中數據的緩存。這種緩存趨向于擁有一個相當高的命中率!Seam優化了集群環境中受管Seam持久化上下文的復制,也不需要保證數據庫事務的一致性(樂觀鎖已足夠),因此你不必擔心這種緩存的性能問題,除非你把成千上萬個對象讀取到一個單獨的持久化上下文中。
應用可以在Seam應用上下文中緩存非事務性狀態。相應的,保存在應用上下文中的狀態不能被集群中其它結點訪問。
應用通過Seam的 pojoCache 組件可以緩存事務性狀態,這個組件把JBossCache集成到了Seam環境中。如果你在集群模式下運行了JBossCache,那么這個狀態是可以被別的結點訪問的。
最后,Seam讓你能夠緩存生成的JSF頁面的部分內容(rendered fragments)。與ORM的二級緩存不一樣的是,當數據發生變化時,這種緩存不能自動的失效,因此你需要寫應用代碼來使它顯式的失效,或者設置適當的過期策略。
如要獲得更多關于二級緩存的信息,你可以參考你的ORM解決方案的文檔,因為這是個極為復雜的話題。在這節中我們會直接討論通過 pojoCache 組件使用JBossCache,或者通過 <s:cache>控制充當頁片段(page fragment)緩存。
EJB 會話Bean有聲明式事務管理功能。當Bean被調用時,EJB容器能夠透明地開始一個事務,在調用結束時關閉此事務。 如果我們寫了一個作為JSF動作監聽器的會話Bean方法,我們就可以在一個事務內處理所有與此action相關的工作,并且當我們完成此動作處理時事務 必須被提交或回滾。 這是一個很棒的功能,在很多Seam應用程序中這是必需的。
但是,此方法還是有問題。Seam應用可能無法在對會話Bean的一次方法調用請求中完成所有的數據訪問。
此請求可能由幾個松耦合組件處理,Web層獨立地調用每一個組件。在Seam中,Web層的一個請求對EJB組件發起幾次甚至多次調用的現象是很常見的。
視圖渲染可能需要延遲關聯獲取(lazy fetching of associations)。
每個請求的事務量越多,當我們的應用處理大量并發請求時越可能碰到原子和隔離問題。當然,所有的寫操作要在一個事務中執行。
Hibernate用戶開發了 "Open Session in View" 模式來解決該問題。 在Hibernate社區,"Open Session in View"曾經非常重要,這是因為像Spring這樣的框架使用了事務作用域持久化上下文。 所以當未獲得的關聯被訪問時渲染視圖將引起 LazyInitializationException 異常。
這 個模式通常作為一個跨越整個請求的事務來實現。 此實現方式會有幾個問題,其中最嚴重的是只有我們提交了事務才能確認它成功完成——但在"Open Session in View"的事務提交時,視圖已經完全渲染了,甚至渲染好的應答可能已經刷新到客戶端。我們怎樣才能通知用戶他們的事務已失敗呢?
Seam在解決"Open Session in View"問題時,也解決了事務隔離和關聯獲取問題。該方案有有兩個部分:
使用使用已擴展持久化上下文,可以覆蓋一個會話作用域而不是單個事務作用域。
每次請求使用兩個事務;第一個從更新模型值的起始階段到應用程序調用結束;第二個跨越渲染響應階段。
很多應用服務器的 HttpSession 集群實 現都有問題,對綁定到Session的可變對象狀態的改變只有在明確調用 setAttribute() 的時候才會被復制。 這是Bug的一個源頭,這些Bug難以在開發階段有效找出,因為它們只會在應用服務器失效切換的時候才會被發現。 而且,實際的復制信息包含了綁定到Session的所有序列化對象圖,這是低效的。
當然,EJB 有狀態Session Bean必須進行自動dirty checking,并進行可變狀態的復制,并且EJB 容器也應該引入優化,例如屬性級別的復制。 但不幸的是,并非所有的Seam用戶都有這么好的運氣,他們的環境可能并不支持EJB 3.0。 因此,對于Session和Conversation范圍內的JavaBean和Entity Bean組件,在Web容器的Session集群之上,Seam提供了額外的集群安全的狀態管理層。