WebWork教程- Interceptor(攔截器)
posted @ 2006-09-01 13:39 Binary 閱讀(616) | 評論 (0) | 編輯 收藏
VincentVicent's blog
隨筆 - 74, 文章 - 0, 評論 - 5, 引用 - 0
|
WebWork教程- Interceptor(攔截器)
摘要: Interceptor
(攔截器)將
Action
共用的行為獨立出來,在
Action
執行前后運行。這也就是我們所說的
AOP
(
Aspect Oriented Programming
,面向切面編程),它是分散關注的編程方法,它將通用需求功能從不相關類之中分離出來;同時,能夠使得很多類共享一個行為,一... 閱讀全文
posted @ 2006-09-01 13:39 Binary 閱讀(616) | 評論 (0) | 編輯 收藏 WebWork介紹-Action篇
摘要: Action
簡介
Action
在
MVC
模式中擔任控制部分的角色
,
在
WebWork
中使用的最多
,
用于接收頁面參數,起到對
HttpRequest
判斷處理作用。每個請求的動作都對應于一個相應的
... 閱讀全文
posted @ 2006-09-01 13:38 Binary 閱讀(231) | 評論 (0) | 編輯 收藏 Log4J學習筆記
posted @ 2006-09-01 13:25 Binary 閱讀(437) | 評論 (0) | 編輯 收藏 Java 技術: 使您輕松地進行多線程應用程序編程
產者-消費者方案是多線程應用程序開發中最常用的構造之一 ― 因此困難也在于此。因為在一個應用程序中可以多次重復生產者-消費者行為,其代碼也可以如此。軟件開發人員 Ze'ev Bubis 和 Saffi Hartal 創建了
Consumer 類,該類通過在一些多線程應用程序中促進代碼重用以及簡化代碼調試和維護來解決這個問題。請通過單擊本文頂部或底部的 討論來參與本文的 論壇,與作者和其他讀者分享您的想法。 多線程應用程序通常利用生產者-消費者編程方案,其中由生產者線程創建重復性作業,將其傳遞給作業隊列,然后由消費者線程處理作業。雖然這種編程方法很有用,但是它通常導致重復的代碼,這對于調試和維護可能是真正的問題。 為了解決這個問題并促進代碼重用,我們創建了 在本文中,我們將簡單觀察一下多線程應用程序開發中公共線程用法,同時,解釋一下生產者-消費者編程方案,并研究一個實際的示例來向您演示 多線程是一種使應用程序能同時處理多個操作的編程技術。通常有兩種不同類型的多線程操作使用多個線程:
適時事件的示例包括程序提醒、超時事件以及諸如輪詢和刷新之類的重復性操作。后臺處理的示例包括等待發送的包或等待處理的已接收的消息。
生產者-消費者方案很適合于后臺處理類別的情況。這些情況通常圍繞一個作業“生產者”方和一個作業“消費者”方。當然,關于作業并行執行還有其它考慮事項。在大多數情況下,對于使用同一資源的作業,應以“先來先服務”的方式按順序處理,這可以通過使用單線程的消費者輕松實現。通過使用這種方法,我們使用單個線程來訪問單個資源,而不是用多個線程來訪問單個資源。 要啟用標準消費者,當作業到來時創建一個作業隊列來存儲所有作業。生產者線程通過將新對象添加到消費者隊列來交付這個要處理的新對象。然后消費者線程從隊列取出每個對象,并依次處理。當隊列為空時,消費者進入休眠。當新的對象添加到空隊列時,消費者會醒來并處理該對象。因為大多數應用程序喜歡順序處理方式,所以消費者通常是單線程的。
因為生產者-消費者方案很常用,所以在構建應用程序時它可能會出現幾次,這導致了代碼重復。我們認識到,這顯示了在應用程序開發過程期間多次使用了生產者-消費者方案的問題。 當第一次需要生產者-消費者行為時,通過編寫一個采用一個線程和一個隊列的類來實現該行為。當第二次需要這種行為時,我們著手從頭開始實現它,但是接著認識到以前已經做過這件事了。我們復制了代碼并修改了處理對象的方式。當第三次在該應用程序中實現生產者-消費者行為時,很明顯我們復制了太多代碼。我們決定,需要一個適用的
我們創建 我們對
在 清單 1. 創建 Consumer 的線程
該線程的 清單 2. run() 方法是主 Consumer 循環
基本上, 使用 清單 3. 喚醒和通知 Consumer
為了向您展示 清單 4. MessagesProcessor 類
正如您可以從上面的代碼中所看到的,定制
除了開始時提出的基本需求以外,我們還為 事件通知
終止
在我們的示例中,如果使用
可在 參考資料一節下載
posted @ 2006-08-24 17:53 Binary 閱讀(252) | 評論 (0) | 編輯 收藏 Java 理論和實踐: 理解 JTS ― 幕后魔術雖然用 Java? 語言編寫的程序在理論上是不會出現“內存泄漏”的,但是有時對象在不再作為程序的邏輯狀態的一部分之后仍然不被垃圾收集。本月,負責保障應用程序健康的工程師 Brian Goetz 探討了無意識的對象保留的常見原因,并展示了如何用弱引用堵住泄漏。 要讓垃圾收集(GC)回收程序不再使用的對象,對象的邏輯 生命周期(應用程序使用它的時間)和對該對象擁有的引用的實際 生命周期必須是相同的。在大多數時候,好的軟件工程技術保證這是自動實現的,不用我們對對象生命周期問題花費過多心思。但是偶爾我們會創建一個引用,它在內存中包含對象的時間比我們預期的要長得多,這種情況稱為無意識的對象保留(unintentional object retention)。 無意識對象保留最常見的原因是使用 清單 1. 使用一個全局 Map 將元數據關聯到一個對象
這種方法的問題是元數據的生命周期需要與套接字的生命周期掛鉤,但是除非準確地知道什么時候程序不再需要這個套接字,并記住從
程序有內存泄漏的第一個跡象通常是它拋出一個 有工具可以利用 GC 日志輸出并以圖形方式將它顯示出來,JTune 就是這樣的一種工具(請參閱 參考資料)。觀察 GC 之后堆大小的圖,可以看到程序內存使用的趨勢。對于大多數程序來說,可以將內存使用分為兩部分:baseline 使用和 current load 使用。對于服務器應用程序,baseline 使用就是應用程序在沒有任何負荷、但是已經準備好接受請求時的內存使用,current load 使用是在處理請求過程中使用的、但是在請求處理完成后會釋放的內存。只要負荷大體上是恒定的,應用程序通常會很快達到一個穩定的內存使用水平。如果在應用程序已經完成了其初始化并且負荷沒有增加的情況下,內存使用持續增加,那么程序就可能在處理前面的請求時保留了生成的對象。 清單 2 展示了一個有內存泄漏的程序。 清單 2. 具有基于 Map 的內存泄漏的程序
圖 1 顯示 圖 1. 持續上升的內存使用趨勢 ![]() 確信有了內存泄漏后,下一步就是找出哪種對象造成了這個問題。所有內存分析器都可以生成按照對象類進行分解的堆快照。有一些很好的商業堆分析工具,但是找出內存泄漏不一定要花錢買這些工具 —— 內置的 清單 3 顯示分解了應用程序內存使用的 請參閱 清單 3。 清單 4 展示了 清單 4. HPROF 輸出,顯示 Map.Entry 對象的分配點
弱引用是對一個對象(稱為 referent)的引用的持有者。使用弱引用后,可以維持對 referent 的引用,而不會阻止它被垃圾收集。當垃圾收集器跟蹤堆的時候,如果對一個對象的引用只有弱引用,那么這個 referent 就會成為垃圾收集的候選對象,就像沒有任何剩余的引用一樣,而且所有剩余的弱引用都被清除。(只有弱引用的對象稱為弱可及(weakly reachable)。)
用一個普通的(強)引用拷貝一個對象引用時,限制 referent 的生命周期至少與被拷貝的引用的生命周期一樣長。如果不小心,那么它可能就與程序的生命周期一樣 —— 如果將一個對象放入一個全局集合中的話。另一方面,在創建對一個對象的弱引用時,完全沒有擴展 referent 的生命周期,只是在對象仍然存活的時候,保持另一種到達它的方法。 弱引用對于構造弱集合最有用,如那些在應用程序的其余部分使用對象期間存儲關于這些對象的元數據的集合 —— 這就是 清單 5. WeakReference.get() 的一種可能實現
調用 在向 在 清單 6. 用 WeakHashMap 修復 SocketManager
可以通過周期性地掃描 引用隊列是垃圾收集器向應用程序返回關于對象生命周期的信息的主要方法。弱引用有兩個構造函數:一個只取 referent 作為參數,另一個還取引用隊列作為參數。如果用關聯的引用隊列創建弱引用,在 referent 成為 GC 候選對象時,這個引用對象(不是 referent)就在引用清除后加入 到引用隊列中。之后,應用程序從引用隊列提取引用并了解到它的 referent 已被收集,因此可以進行相應的清理活動,如去掉已不在弱集合中的對象的項。(引用隊列提供了與
清單 7. WeakHashMap.expungeStaleEntries() 的可能實現
弱引用和弱集合是對堆進行管理的強大工具,使得應用程序可以使用更復雜的可及性方案,而不只是由普通(強)引用所提供的“要么全部要么沒有”可及性。下個月,我們將分析與弱引用有關的軟引用,將分析在使用弱引用和軟引用時,垃圾收集器的行為。 posted @ 2006-08-24 17:51 Binary 閱讀(216) | 評論 (0) | 編輯 收藏 Java 理論與實踐: 您的小數點到哪里去了?許多程序員在其整個開發生涯中都不曾使用定點或浮點數,可能的例外是,偶爾在計時測試或基準測試程序中會用到。Java語言和類庫支持兩類非整數類型 ― IEEE 754 浮點( 雖然幾乎每種處理器和編程語言都支持浮點運算,但大多數程序員很少注意它。這容易理解 ― 我們中大多數很少需要使用非整數類型。除了科學計算和偶爾的計時測試或基準測試程序,其它情況下幾乎都用不著它。同樣,大多數開發人員也容易忽略 Java 語言支持兩種基本的浮點類型: IEEE 754 用科學記數法以底數為 2 的小數來表示浮點數。IEEE 浮點數用 1 位表示數字的符號,用 8 位來表示指數,用 23 位來表示尾數,即小數部分。作為有符號整數的指數可以有正負之分。小數部分用二進制(底數 2)小數來表示,這意味著最高位對應著值 ?(2 -1),第二位對應著 ?(2 -2),依此類推。對于雙精度浮點數,用 11 位表示指數,52 位表示尾數。IEEE 浮點值的格式如圖 1 所示。 圖 1. IEEE 754 浮點數的格式 ![]() 因為用科學記數法可以有多種方式來表示給定數字,所以要規范化浮點數,以便用底數為 2 并且小數點左邊為 1 的小數來表示,按照需要調節指數就可以得到所需的數字。所以,例如,數 1.25 可以表示為尾數為 1.01,指數為 0: 數 10.0 可以表示為尾數為 1.01,指數為 3: 除了編碼所允許的值的標準范圍(對于 這些特殊的數字有一些不尋常的特征。例如,
使事情更糟的是,在基本
由于無窮大、NaN 和
浮點運算很少是精確的。雖然一些數字(譬如
類似的,
將得到以下輸出:
這可能不是您起初所期望的。
由于存在 NaN 的不尋常比較行為和在幾乎所有浮點計算中都不可避免地會出現舍入誤差,解釋浮點值的比較運算符的結果比較麻煩。 最好完全避免使用浮點數比較。當然,這并不總是可能的,但您應該意識到要限制浮點數比較。如果必須比較浮點數來看它們是否相等,則應該將它們差的絕對值同一些預先選定的小正數進行比較,這樣您所做的就是測試它們是否“足夠接近”。(如果不知道基本的計算范圍,可以使用測試“abs(a/b - 1) < epsilon”,這種方法比簡單地比較兩者之差要更準確)。甚至測試看一個值是比零大還是比零小也存在危險 ―“以為”會生成比零略大值的計算事實上可能由于積累的舍入誤差會生成略微比零小的數字。 NaN 的無序性質使得在比較浮點數時更容易發生錯誤。當比較浮點數時,圍繞無窮大和 NaN 問題,一種避免 gotcha 的經驗法則是顯式地測試值的有效性,而不是試圖排除無效值。在清單 1 中,有兩個可能的用于特性的 setter 的實現,該特性只能接受非負數值。第一個實現會接受 NaN,第二個不會。第二種形式比較好,因為它顯式地檢測了您認為有效的值的范圍。 清單 1. 需要非負浮點值的較好辦法和較差辦法
一些非整數值(如幾美元和幾美分這樣的小數)需要很精確。浮點數不是精確值,所以使用它們會導致舍入誤差。因此,使用浮點數來試圖表示象貨幣量這樣的精確數量不是一個好的想法。使用浮點數來進行美元和美分計算會得到災難性的后果。浮點數最好用來表示象測量值這類數值,這類值從一開始就不怎么精確。
從 JDK 1.3 起,Java 開發人員就有了另一種數值表示法來表示非整數: 用于加、減、乘和除的方法給 如浮點類型一樣, 另外還有一些情形,任意精度的小數運算仍不能表示精確結果。例如, SQL-92 包括 如果希望將數字存儲到數據庫中的 對于 對于 如果使用
在執行這段似乎無害的代碼時會拋出一些令人迷惑不解的異常(這取決于具體的 JDBC 驅動程序),因為
在 Java 程序中使用浮點數和小數充滿著陷阱。浮點數和小數不象整數一樣“循規蹈矩”,不能假定浮點計算一定產生整型或精確的結果,雖然它們的確“應該”那樣做。最好將浮點運算保留用作計算本來就不精確的數值,譬如測量。如果需要表示定點數(譬如,幾美元和幾美分),則使用 posted @ 2006-08-24 17:51 Binary 閱讀(253) | 評論 (0) | 編輯 收藏 Java 理論與實踐: 變還是不變?不變對象具有許多能更方便地使用它們的特性,包括不嚴格的同步需求和不必考慮數據訛誤就能自由地共享和高速緩存對象引用。盡管不變性可能未必對于所有類都有意義,但大多數程序中至少有一些類將受益于不可變。在本月的 Java 理論與實踐中,Brian Goetz 說明了不變性的一些長處和構造不變類的一些準則。請在附帶的 論壇中與作者和其他讀者分享您關于本文的心得。(也可以單擊文章頂部或底部的“討論”來訪問論壇。) 不變對象是指在實例化后其外部可見狀態無法更改的對象。Java 類庫中的 如果正確使用不變類,它們會極大地簡化編程。因為它們只能處于一種狀態,所以只要正確構造了它們,就決不會陷入不一致的狀態。您不必復制或克隆不變對象,就能自由地共享和高速緩存對它們的引用;您可以高速緩存它們的字段或其方法的結果,而不用擔心值會不會變成失效的或與對象的其它狀態不一致。不變類通常產生最好的映射鍵。而且,它們本來就是線程安全的,所以不必在線程間同步對它們的訪問。 因為不變對象的值沒有更改的危險,所以可以自由地高速緩存對它們的引用,而且可以肯定以后的引用仍將引用同一個值。同樣地,因為它們的特性無法更改,所以您可以高速緩存它們的字段和其方法的結果。 如果對象是可變的,就必須在存儲對其的引用時引起注意。請考慮清單 1 中的代碼,其中排列了兩個由調度程序執行的任務。目的是:現在啟動第一個任務,而在某一天啟動第二個任務。 清單 1. 可變的 Date 對象的潛在問題
因為 大多數的線程安全問題發生在當多個線程正在試圖并發地修改一個對象的狀態(寫-寫沖突)時,或當一個線程正試圖訪問一個對象的狀態,而另一個線程正在修改它(讀-寫沖突)時。要防止這樣的沖突,必須同步對共享對象的訪問,以便在對象處于不一致狀態時其它線程不能訪問它們。正確地做到這一點會很難,需要大量文檔來確保正確地擴展程序,還可能對性能產生不利后果。只要正確構造了不變對象(這意味著不讓對象引用從構造函數中轉義),就使它們免除了同步訪問的要求,因為無法更改它們的狀態,從而就不可能存在寫-寫沖突或讀-寫沖突。 不用同步就能自由地在線程間共享對不變對象的引用,可以極大地簡化編寫并發程序的過程,并減少程序可能存在的潛在并發錯誤的數量。 把對象當作參數的方法不應變更那些對象的狀態,除非文檔明確說明可以這樣做,或者實際上這些方法具有該對象的所有權。當我們將一個對象傳遞給普通方法時,通常不希望對象返回時已被更改。但是,使用可變對象時,完全會是這樣的。如果將 不變對象產生最好的 清單 2. 可變 StringHolder 類,不適合用作鍵
不變類最適合表示抽象數據類型(如數字、枚舉類型或顏色)的值。Java 類庫中的基本數字類(如
Java 類庫中不變性的另一個不錯的示例是 如果要表示的對象是多個基本值的容器(如:點、向量、矩陣或 RGB 顏色),是用可變對象還是用不變對象表示?答案是……要看情況而定。要如何使用它們?它們主要用來表示多維值(如像素的顏色),還是僅僅用作其它對象的一組相關特性集合(如窗口的高度和寬度)的容器?這些特性多久更改一次?如果更改它們,那么各個組件值在應用程序中是否有其自己的含義呢? 事件是另一個適合用不變類實現的好示例。事件的生命期較短,而且常常會在創建它們的線程以外的線程中消耗,所以使它們成為不變的是利大于弊。大多數 AWT 事件類都沒有作為嚴格的不變類來實現,而是可以有小小的修改。同樣地,在使用一定形式的消息傳遞以在組件間通信的系統中,使消息對象成為不變的或許是明智的。
編寫不變類很容易。如果以下幾點都為真,那么類就是不變的:
最后一組要求似乎挺復雜的,但其基本上意味著如果要存儲對數組或其它可變對象的引用,就必須確保您的類對該可變對象擁有獨占訪問權(因為不然的話,其它類能夠更改其狀態),而且在構造后您不修改其狀態。為允許不變對象存儲對數組的引用,這種復雜性是必要的,因為 Java 語言沒有辦法強制不對 final 數組的元素進行修改。注:如果從傳遞給構造函數的參數中初始化數組引用或其它可變字段,您必須用防范措施將調用程序提供的參數或您無法確保具有獨占訪問權的其它信息復制到數組。否則,調用程序會在調用構造函數之后,修改數組的狀態。清單 3 顯示了編寫一個存儲調用程序提供的數組的不變對象的構造函數的正確方法(和錯誤方法)。 清單 3. 對不變對象編碼的正確和錯誤方法
通過一些其它工作,可以編寫使用一些非 final 字段的不變類(例如,
有些數據項在程序生命期中一直保持常量,而有些會頻繁更改。常量數據顯然符合不變性,而狀態復雜且頻繁更改的對象通常不適合用不變類來實現。那么有時會更改,但更改又不太頻繁的數據呢?有什么方法能讓 有時更改的數據獲得不變性的便利和線程安全的長處呢?
除了在修改列表時,
使用不變對象比使用可變對象要容易得多。它們只能處于一種狀態,所以始終是一致的,它們本來就是線程安全的,可以被自由地共享。使用不變對象可以徹底消除許多容易發生但難以檢測的編程錯誤,如無法在線程間同步訪問或在存儲對數組或對象的引用前無法克隆該數組或對象。在編寫類時,問問自己這個類是否可以作為不變類有效地實現,總是值得的。您可能會對回答常常是肯定的而感到吃驚。 posted @ 2006-08-24 17:50 Binary 閱讀(213) | 評論 (0) | 編輯 收藏 JDBC 查詢日志變得簡單JDBC java.sql.PreparedStatement接口的簡單擴展可以使查詢記錄更少犯錯,同時整理您的代碼。在本文中,IBM電子商務顧問Jens Wyke向您介紹如何應用基本的封裝技術(“通過封裝來實現擴展”也稱為Decorator設計模式)來獲得最滿意的結果。 在大多數情況下,JDBC 在本文中,您將了解到如何擴展JDBC 注意:本文假設您有豐富的JDBC和 表1介紹了數據庫查詢時通常是如何使用 表1:一個典型的SQL數據庫查詢
表1中一個好的查詢日志條目看起來應與下面有幾分類似:
下面是查詢的日志代碼的一個例子。注意:表1中的問號已經被每個參數的值替換。
一種更好的方法是創建方法,我們稱之為 表 2:使用replaceFirstQuestionMark來進行字符串替換
雖然這些解決方案都易于實施,但沒有一種是完美的。問題是在更改SQL模板的同時也必須更改日志代碼。您將在某一點上犯錯幾乎是不可避免的。查詢將更改但您忘記了更新日志代碼,您將結束與將發送到數據庫的查詢不匹配的日志條目 -- 調試惡夢。 我們真正需要的是一種使我們能夠一次性使用每個參數變量(在我們的實例中為
我們的 表3介紹了 表3:LoggableStatement實現java.sql.PreparedStatement
表4介紹了 表4:LoggableStatement 方法
表5中顯示了 表5:saveQueryParamValue()方法
當我們使用標準方法來設置所有參數時,我們在
表6顯示如何更改表1和表2中的代碼來使用 表6:使用LoggableStatement 
使用本文介紹的非常簡單的步驟,您可以為查詢記錄擴展JDBC posted @ 2006-08-24 17:50 Binary 閱讀(249) | 評論 (0) | 編輯 收藏 使用Jakarta Commons Pool處理對象池化
摘要: 恰當地使用對象池化技術,可以有效地減少對象生成和初始化時的消耗,提高系統的運行效率。Jakarta Commons Pool組件提供了一整套用于實現對象池化的框架,以及若干種各具特色的對象池實現,可以有效地減少處理對象池化時的工作量,為其它重要的工作留下更多的精力和時間。
創建新的對象并初始化的操作,可能會消耗很多的時間。在這種對象的初始化工作包含了一些費時的操作(例... 閱讀全文
posted @ 2006-08-24 17:49 Binary 閱讀(244) | 評論 (0) | 編輯 收藏 Java 理論和實踐: 理解 JTS ― 幕后魔術在這個系列的 第 1 部分,我們討論了事務并研究了它們的基本屬性 ― 原子性(atomicity)、一致性(consistency)、孤立性(isolation)和持久性(durability)。事務是企業應用程序的基本構件;沒有它們,幾乎不可能構建有容錯能力的企業應用程序。幸運的是,Java 事務服務(Java Transaction Service,JTS)和 J2EE 容器自動為您做了大量的事務管理工作,這樣您就不必將事務意識直接集成到組件代碼中。結果簡直是一種魔術 ― 通過遵守幾條簡單的規則,J2EE 應用程序就可以自動獲得事務性語義,只需極少或根本不需要額外的組件代碼。本文旨在通過展示事務管理如何發生,以及發生在何處來揭開這個魔術的神秘面紗。 JTS 是一個 組件事務監視器(component transaction monitor)。這是什么意思?在第 1 部分,我們介紹了 事務處理監視器(TPM)這個概念,TPM 是一個程序,它代表應用程序協調分布式事務的執行。TPM 與數據庫出現的時間長短差不多;在 60 年代后期,IBM 首先開發了 CICS,至今人們仍在使用。經典的(或者說 程序化)TPM 管理被程序化定義為針對事務性資源(比如數據庫)的操作序列的事務。隨著分布式對象協議,如 CORBA、DCOM 和 RMI 的出現,人們希望看到事務更面向對象的前景。將事務性語義告知面向對象的組件要求對 TPM 模型進行擴展 ― 在這個模型中事務是按照事務性對象的調用方法定義的。JTS 只是一個組件事務監視器(有時也稱為 對象事務監視器(object transaction monitor)),或稱為 CTM。 JTS 和 J2EE 的事務支持設計受 CORBA 對象事務服務(CORBA Object Transaction Service,OTS)的影響很大。實際上,JTS 實現 OTS 并充當 Java 事務 API(Java Transaction API)― 一種用來定義事務邊界的低級 API ― 和 OTS 之間的接口。使用 OTS 代替創建一個新對象事務協議遵循了現有標準,并使 J2EE 和 CORBA 能夠互相兼容。 乍一看,從程序化事務監視器到 CTM 的轉變好像只是術語名稱改變了一下。然而,差別不止這一點。當 CTM 中的事務提交或回滾時,與事務相關的對象所做的全部更改都一起被提交或取消。但 CTM 怎么知道對象在事務期間做了什么事?象 EJB 組件之類的事務性組件并沒有
當應用程序狀態被組件操縱時,它仍然存儲在事務性資源管理器(例如,數據庫和消息隊列服務器)中,這些事務性資源管理器可以注冊為分布式事務中的資源管理器。在第 1 部分中,我們討論了如何在單個事務中征用多個資源管理器,事務管理器如何協調這些資源管理器。資源管理器知道如何把應用程序狀態中的變化與特定的事務關聯起來。 但這只是把問題的焦點從組件轉移到了資源管理器 ― 容器如何斷定什么資源與該事務有關,可以供它征用?請考慮下面的代碼,在典型的 EJB 會話 bean 中您可能會發現這樣的代碼: 清單 1. bean 管理的事務的透明資源征用
注意,這個示例中沒有征用當前事務中 JDBC 連接的代碼 ― 容器會為我們完成這個任務。我們來看一下它是如何發生的。 當一個 EJB 組件想訪問數據庫、消息隊列服務器或者其它一些事務性資源時,它需要到資源管理器的連接(通常是使用 JNDI)。而且,J2EE 規范只認可三種類型的事務性資源 ― JDBC 數據庫、JMS 消息隊列服務器和“其它通過 JCA 訪問的事務性服務”。后面一種服務(比如 ERP 系統)必須通過 JCA(J2EE Connector Architecture,J2EE 連接器體系結構)訪問。對于這些類型資源中的每一種,容器或提供者都會幫我們把資源征調到事務中。 在清單 1 中, 每個 J2EE 容器都可以創建有事務意識的池態 每個容器(或連接池管理器,如 PoolMan)都提供它自己的創建 其它類型的事務性資源,JMS 消息隊列和 JCA 連接器,依靠相似的機制將資源征用隱藏起來,使用戶看不到。如果要使 JMS 隊列在部署時對 J2EE 應用程序可用,您就要再次使用特定于提供者的機制來創建受管 JMS 對象(隊列連接工廠和目標),然后在 JNDI 名稱空間內發布這些對象。提供者創建的受管對象包含與 JDBC 包裝器(由容器提供的連接池管理器添加)相似的自動征用代碼。
兩種類型的 J2EE 事務 ― 容器管理的和 bean 管理的 ― 在如何啟動和結束事務上是不同的。事務啟動和結束的地方被稱為 事務劃分(transaction demarcation)。清單 1 中的示例代碼演示了 bean 管理的事務(有時也稱為 編程(programmatic)事務)。Bean 管理的事務是由組件使用 容器根據組件的部署描述符中的事務屬性代表應用程序透明地啟動和結束容器管理的事務(或稱為 宣告式事務(declarative transaction))。通過將 使用容器管理的事務,您可以在 EJB 類或方法級別上指定事務性屬性;您可以為 EJB 類指定缺省的事務性屬性,如果不同的方法會有不同的事務性語義,您還可以為每個方法指定屬性。這些事務性屬性在裝配描述符(assembly descriptor)的
清單 2. EJB 裝配描述符樣本
與清單 1 中的示例不同,由于有宣告式事務劃分,這段組件代碼中沒有事務管理代碼。這不僅使結果組件代碼更加易讀(因為它不與事務管理代碼混在一起),而且它還有另一個更重要的優點 ― 不必修改,甚至不必訪問組件的源代碼,就可以在應用程序裝配時改變組件的事務性語義。 盡管能夠指定與代碼分開的事務劃分是一種非常強大的功能,但在裝配時做出不好的決定會使應用程序變得不穩定,或者嚴重影響它的性能。對容器管理的事務進行正確分界的責任由組件開發者和應用程序裝配人員共同擔當。組件開發者需要提供足夠的文檔說明組件是做什么的,這樣應用程序部署者就能夠明智地決定如何構建應用程序的事務。應用程序裝配人員需要理解應用程序中的組件是怎樣相互作用的,這樣就可以用一種既強制應用程序保持一致又不削弱性能的方法對事務進行分界。在這個系列的第 3 部分中我們將討論這些問題。
在任何類型的事務中,資源征用都是透明的;容器自動將事務過程中使用的任意事務性資源征調到當前事務中。這個過程不僅擴展到事務性方法使用的資源(比如在清單 1 中獲得的數據庫連接),還擴展到它調用的方法(甚至遠程方法)使用的資源。我們來看一下這是如何發生的。 我們假設對象 當事務啟動時,事務上下文與執行線程關聯在一起。當 如果對象 事務可以由任何 J2EE 組件來啟動 ― 一個 EJB 組件、一個 servlet 或者一個 JSP 頁面(如果容器支持的話,還可以是一個應用程序客戶機)。這意味著,應用程序可以在請求到達時在 servlet 或者 JSP 頁面中啟動事務、在 servlet 或者 JSP 頁面中執行一些處理、作為頁面邏輯的一部分訪問多個服務器上的實體 bean 和會話 bean 并使所有這些工作透明地成為一個事務的一部分。圖 1 演示了事務上下文怎樣遵守從 servlet 到 EJB,再到 EJB 的執行路徑。 圖 1.單個事務中的多個組件 ![]()
讓容器來管理事務允許容器為我們做出某些最優化決定。在圖 1 中,我們看到一個 servlet 和多個 EJB 組件在單個事務的上下文中訪問一個數據庫。每個組件都獲得到數據庫的
這個慮及透明事務控制、資源征用和透明傳播的魔術不是 JTS 的一部分,而是 J2EE 容器如何在幕后代表 J2EE 應用程序使用 JTA 和 JTS 服務的一部分。在幕后有許多實體合力使這個魔術透明地發生;EJB 存根和骨架、容器廠商提供的 JDBC 驅動器包裝器、數據庫廠商提供的 JDBC 驅動器、JMS 提供器和 JCA 連接器。所有這些實體都與事務管理器進行交互,于是應用程序代碼就不必與之交互了。 在第 3 部分,我們將看一下關于管理 J2EE 上下文中事務的一些實際問題 ― 事務劃分和孤立 ― 以及它們對應用程序一致性、穩定性和性能的影響。 posted @ 2006-08-24 17:47 Binary 閱讀(257) | 評論 (0) | 編輯 收藏 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||