j2ee|程式
在不久前的一段時間內,Java 開發人員在準備一個新的企業 Java 開發項目時,事先就知道將要使用的工具。當時,一切都很簡單:J2EE 是新的,HTML 瀏覽器是公認的使用者介面標準,而複雜性(至少從推測的角度而言)已成為過去的事情。而如今,事情變得如此複雜。
“開發人員面對的選擇令人眼花繚亂。”
開發人員面對的選擇令人眼花繚亂,從“輕型容器”(如 Spring、NanoContainer 或 HiveMind)到“web 架構”(如 WebWork、Tapestry(一個基於 JSF 的 UI,類似於 Oracle 的新應用程式開發架構 (Oracle ADF))或 Velocity)。這些選擇還增加了一系列新的 J2EE 規範,或者說是通過 JAXM、SAAJ、JAX-RPC 或 JAX 對“Web 服務”和相應的新技術術語“服務導向架構”賦予了新的價值(更不用提“WS-*”規範、工具和庫了),Java 開發人員可以完成所有工作,這真是一個奇蹟。
No Fluff Just Stuff 軟體論文系列的演講者 Ben Galbraith 將此現象稱作“Java 架構不確定性原則”:“您剛剛選擇了一個架構,某個其他架構的新版本便發布了,從而迫使您對選擇架構重新分析。”而且這種情況的複雜程度也無以複加了:只需將核心 J2EE 和 J2SE 類混合在一起使用。畢竟,我們被告知 EJB 是 J2EE 的“核心”,並且考慮一個沒有 EJB 的企業 Java 項目將是一個愚蠢的想法,這隻是昨天的事。究竟泛型如何改變您的 J2EE 編碼體驗?並且到底是誰讓所有 Java 管理擴充成了路障?
到底是怎麼了?最初明確專註於建立一個由單項優勢工具和庫構成的平台的行業何以在如此短的時間內變得如此零亂?我們何時需要在傳統的“J2EE”工具(如 EJB)與新型“Web 服務”(如 JAXRPC 和 WS-Security)工具之間進行選擇?更重要的是,我們現在如何做才能避免 Ben 的 Java 架構不確定性原則而又不違背 Java 首先應遵循的供應商無關原則?
此問題主要在於瞭解最能滿足需要的技術,而最好的方法是首先瞭解應用程式的需要。瞭解應用程式的需要後,即可清楚地界定應選用的相應技術。
本文將簡要概述最先進的 J2EE、與其相關的技術以及 Java 開發人員當今面臨的某些體繫結構挑戰。
我們如今要走向何處?
很多不同類型的 Java 程式在“企業 Java”的名義下趨於變得臃腫,在深入討論前,這也許有助於將它們與其他類型的 Java 應用程式區分開。如果我們從傳統的“3 層”方法開始(即將表示、商務邏輯和資料訪問劃分為三個一致的設計層次),則我們實際上可以確定五種“企業”Java 應用程式:煙囪、寶石、彙總器、整合器和公司專屬應用程式程式。
“我們實際上可以確定五種“企業”Java 應用程式:煙囪、寶石、彙總器、整合器和公司專屬應用程式程式”。
煙囪煙囪應用程式(也稱作“豎井”)可能是開發人員最容易接受的應用程式,這是因為它是一種我們一再開發的應用程式:它是傳統的“單資料庫、單 UI”應用程式,就絕對數量而言,它是當前構建最廣的一種 IT 應用程式。它通常是根據某個部門經理或副經理的需要(即尋找某個特定工具或應用程式來收集、操作和顯示某種當前未收集、操作和顯示的資料)而開始建立的,為此將組建一個團隊(規模通常不超過三到四個人,往往只有一個人)來收集需求、建立用例、構建資料庫、對商務邏輯進行編碼、將其部署到選擇作為此應用程式的生產伺服器的機器並不斷地監視它。
當然,此名稱得自您在白板上繪製的三個框(表示系統的邏輯層 — 展示層、商務邏輯層和資料訪問層)所形成的映像 — 它們構成了一條垂直線,不由使人想起將燃燒木頭的火爐中產生的煙排出到房間外面的舊式“煙囪”。(順便說一下,對於將該術語用作貶義術語的使用者而言,請記住,您在一生中將使用的許多最重要的系統(如 ATM 機、主要船運公司場地上的包裹定位器等)都是煙囪系統。
有一點可能比較令人吃驚的是,J2EE 軟體套件並不能完全滿足構建簡單煙囪系統的開發人員的需要。當只需要一個展示層,且只有一個資源用於儲存和檢索資料時,J2EE 套件(尤其是 EJB)就顯得“礙事”了。更誘人的方法是考慮輕型架構,因為它們並不那麼專註於部署描述符,並且就 JNDI、JMS 之類而言也沒什麼不便的。它只是通過 網頁瀏覽器進行的基本請求/響應通訊,通常構建在類似 Struts 或相似的 MVC 樣式 web 架構中,並與一組核心的傳統 Java 對象(有時與單個機器上啟動並執行展示層和商務邏輯層(而非資料庫本身))進行通訊。(您可能奇怪此處為什麼沒有使用術語“資料庫”。原因很簡單,雖然大多數項目使用資料庫(而且還是關聯式資料庫)儲存資料,但資料存放區通常是原有系統、商業軟體程式包或形如 CICS 大型主機、SAP 或 BizTalk 的“中介”技術。使用更一般的術語“資源”有助於強調這樣一個看法:後端實現確實與本討論無關。)
煙囪應用程式的另一個優勢是它們通常是“獨立的” — 也就是說不涉及其他應用程式。幾乎不需要遵守任何已建立的安全、可靠性或管理標準,這是因為此應用程式所確立的所有內容都將成為標準(至少對此應用程式而言是這樣,這正是此範圍的關鍵所在)。開發人員經常利用此事實來構建正好適合於此應用程式的基礎架構,從而消除了通常針對企業 Java 應用程式的指責:它們太複雜了,以至於無法使用和維護。
儘管人們希望如此,但 J2EE 的設計並非是針對煙囪應用程式的 — 當然,一個基於 J2EE 的應用程式可以構建此類應用程式(並且有上千個樣本可以作為此事實的證據),事實上有點像用牛刀殺雞。基於 J2EE 的應用程式實施了一定程度的層劃分,但有時這種劃分對於解決手頭的問題顯得有些矯枉過正,如傳統的“10 使用者”煙囪系統。當然,問題是 10 使用者煙囪系統通常有一種另人不悅的趨勢,即轉變為其他四個版本中的某個版本,這樣將使事情變得很糟。就像某位哲學家說的那樣“沒有哪個人是孤立的”,我們也可以很輕鬆和準確地說“沒有哪個系統是孤立的”。至少在短期內是這樣。(當然,如果系統無法完成其預期的目標,那它就無法與任何其他系統整合,並且可能停產,但我們將假設那不是預期的目標。)
珠寶 我們並不是說這是 IT 環境的成功和驕傲或五種應用程式樣式中“最好”的一個,但珠寶樣式的應用程式是結合了多個展示層的應用程式(因此,它的名稱--“珠寶”表示有很多面可供查看)。但請注意,給定展示層可能根本不是供使用者查看的;公司當前經常探討的一個層是其基於 Web 服務的應用程式前端,它並非為人使用而設。儘管如此,該 Web 服務仍表示一個展示層,這是因為它從根本上執行同一操作:擷取輸入並從其下面的核心商務邏輯層中提供輸出。
由於一度曾存在的某些假設突然間不複存在了,珠寶應用程式對傳統編程模型進行了一些有趣的轉變。例如,當考慮一個 Web 服務前端時,突然必須以某種平台和語言無關的方式(對此,XML 模式是當前可以選擇的工具)定義類型,而理想情況下,“一次且僅此一次”規則(也稱作“不重複自身”原則)將允許我們直接通過基於 HTML 的展示層用來與商務邏輯層通訊的同一類型構建此類型。這就是某些 JAX* 規範的用武之地--例如,Java API for XML Binding 有助於定義一個以非常模糊的方式進行“對象到 XML 以及 XML 到對象”轉換的標準方法,而 Java API for XML RPC (JAX-RPC) 定義一種使用 WSDL、SOAP 和 XML 構建可互操作的要求-回應遠程通訊層的方法。
儘管任何事物都不能阻止開發人員從其最愛的輕型容器中使 JAX* 規範,而 J2EE 1.4 規範直接將 JAXRPC 和 JAXB 整合到它的總體技術套件中,從而使您可以將 EJB 無狀態會話 bean 提供為 WSL 1.1/SOAP 1.1 RPC/encoded Web 服務。(請注意,根據 WS-Interoperability Basic Profile 規範,RPC/編碼的服務正式不支援文檔/文字服務;人們普遍期望此差別在 JAX* 和 J2EE 規範的下個版本中得到解決,具體的實現應大概在開發人員實際指出RPC/編碼的服務和文檔/文字服務之間的差別時推出。)此外,商業應用伺服器供應商正竭盡全力確保其產品不僅完全與 J2EE 標準相容,而且還與 Web 服務標準相容。顯而易見,這種情況下用“相容且具競爭力”來形容供應商的動機(包括 J2EE 的主要競爭者,來自西北太平洋的那家不知名的軟體公司的動機)再恰當不過。
順便說的是,打算構建 Web 服務表示 facet 時,值得一提的是,最好使用 JAXB 或 Oracle 的開發人員工具包將系統的模型對象直接提供為 XML 類型,並將整個 Web 服務前端代碼產生為大型 WSDL 文檔。儘管這起初似乎是某個使用者的商務邏輯層的良好驗證(畢竟,如果展示層中真的沒有什麼商務規則,那麼採用此方法其實並不困難),但 Web 服務技術套件中的限制很快便使這個期望變得很難實現。
例如,考慮基於引用的對象與 XML 的關係:應如何最佳地表示一個在 XML 中值為空白的 java.util.Date 引用?尤其是在 .NET 中,Date 根本不是基於引用的對象,而是“實值型別”,這意味著它的作用類似於 int 在 Java 中的作用嗎?當嘗試表示 XML 對象的複雜循環圖表時,事情將變得非常棘手,這就是為什麼原來反對 RPC/編碼的服務的原因之一。這是 WS-* 套件背後所要做的所有工作,但即使某個團隊決定“走自己的路”並構建他們自己的 XML-over-HTTP 系統,他們也要面對同一核心問題。正在嘗試將對象-XML 映射整合到核心產品(如 Oracle Toplink)中,但到目前為止,它們仍處於初始階段。
同時,我們不能忽略那些旨在填補傳統的基於瀏覽器應用程式中的大漏洞以實現“更大的響應性”的新潮展示層方法(“智能”用戶端或“富”用戶端”)。HTML 儘管有很多優點,但也存在一些根本性的缺點,很容易地就想到了兩個:
最小公分母角度。HTML 最初用於儘可能晚地延遲表示決策,標準 HTML 中實際上只有非常少的元素保證在任何給定系統上的呈現外觀。為頁面產生器提供更大控制(如 CSS)的嘗試已經取得了多方面的成功,尤其是在跨不同瀏覽器方面。
表示代碼必須與內容一起發送。由於瀏覽器本身不瞭解應用程式,因此必須在每個網路往返中向伺服器發送表示代碼和內容。此方法有兩個負面影響,一個是頻寬較低(每個用戶端的消耗越高,同一硬體的用戶端數越少),另一個是可用性遭到破壞(如果伺服器或介入的任何拓撲出現故障,則應用程式將不存在)。
為實現此目的,公司專屬應用程式程式供應商正積極考慮將展示層代碼置於終端使用者的機器中,以便完全或部分消除 HTML 的兩個主要缺點。這創造了一些有趣的部署暗示,但許多商店正尋求同時建立瘦用戶端和富用戶端展示層—富用戶端用於公司防火牆的內部,而瘦用戶端用於公司的外部(再次證明您不能太富或太瘦)。此方法招致了必須處理兩個不同架構的麻煩,但至少我們願意擁有一種將資料從使用者輸入傳遞到後端存放庫的統一方法,而且最好能夠針對“富”用戶端和“瘦”用戶端將這種傳遞進行某種形式的標準化 — 由此便產生了 JSR 227,一個通用的資料繫結架構。
“我們願意擁有一個將資料從使用者輸入傳遞到後端存放庫的統一方法;因此,便產生了 JSR 227。”
彙總器正如系統可以提供多個“進入點”一樣,如果您願意,系統還可以建立在多個後端的基礎上,從而從不同的資源收集資料並按一致和有意義的方式顯示它。(既然顯示和操作的資料是多個資源/資料庫的彙總,因此也就有了術語“彙總器”。)並且,在開始建立此彙總資料的操作和儲存用例的 30 秒之後,顯而易見的是,必須使用某種類型的原子性以便兩個資料庫所做的修改保持同步。這正是 Java 事務 API(以及它之前的 X/A 規範)的用途,而交易處理和商務邏輯的交叉部分則是 EJB 產生的原因。
但它不僅僅是事務。多個資源所帶來的不僅僅是兩個不同的資料庫 — 有時,系統需要的可靠性要高於單個資料庫機器所能提供的可靠性。畢竟,系統中任何位置的單個機器只表示單個故障點,而且通常情況下(除所有“熱交換”故障切換情況以外),我們只需關閉資料庫以對其執行某些預定的維護 — 可能包括新的模式更改以滿足代碼變換。Java 命名和目錄介面 (JNDI) 用作所有“尋找”操作的單個 API,從實際底層物理資料庫機器中提供一個間接層,這意味著如果不緩衝 JNDI 尋找結果,則管理員可以更改 JNDI 入口,以從一台機器指向不同的機器,同時 J2EE 應用程式將簡單地進行相應的調整,從而將建立一個無縫和透明的指向新資料庫的“開關”,這在沒有間接層的情況下是無法實現的。
整合器
當需要串連兩個單獨維護的商務邏輯集合時,整合器系統將發揮作用,並且必須開始考慮煙囪系統從不需要的互通性。例如,如果必須執行傳統的要求-回應服務,那麼如何執行請求和響應?開發人員通常立刻求助於 WS-* 服務,但如上所述,WS-* 規範有時太多(並且在當前實現中太不成熟),以至於無法可靠地滿足整合/互通性的需要。而 J2EE 規範通過要求每個 EJB 容器符合 CORBA 調用(意味著任何 CORBA 用戶端可以與 EJB 容器中封裝的商務邏輯互動)再次滿足了此需要。
但並非所有整合均以要求-回應的方式進行。為避免 RPC 和要求-回應通訊的非同步本質中暗藏的瓶頸,許多系統選擇使用基於訊息的方法相互整合。基於訊息的方法是 Java Message Service規範(以及關聯的實現,如 Oracle 的進階隊列)以及/或 Java API for XML Messaging (JAXM) 及其關聯的 SOAP API for Attachments in Java (SAAJ)(用於執行“使用角括弧的訊息傳遞”)的用武之地。
資料庫本身還用作整合層,但與傳統 RPC 或訊息驅動系統並不相同。很多情況下,整合和互通性僅僅體現在將程式“A”中的資料傳遞到程式“B”,而資料庫(以及其他資源)通常用作不同平台(尤其是 J2EE 和 .NET)的有用(和理解充分)的中介語言。儘管它並不滿足所有互通性的需要,但對於許多系統而言,此方法剛好滿足需要 — 它具有自身的好處,尤其是當商務邏輯(通過預存程序)嵌入到資料庫中時。此外,.NET 無需瞭解如何調用駐留在 EJB 伺服器中的 Java 代碼,Java 也無需瞭解如何調用駐留在 COM+ ServicedComponent 中的 .NET 代碼,或如何在兩者之間共用單個分散式交易 ID,等等。尤其是考慮到這樣一個事實:Oracle 允許您在 Java 而非 PL/SQL 中編寫預存程序,從而簡化了預存程序的編寫。
公司專屬應用程式程式 最後,我們瞭解一下“真正的”公司專屬應用程式程式,它是以下三個層的多個 facet 的融合:展示層、邏輯層和資料訪問層。傳統的企業系統需要使用遍布多個應用程式、語言或平台的商務規則集合以各種格式顯示多個資源中的資料。公司專屬應用程式程式最具複雜性,而這正是 J2EE 的強項。此外,由於伴隨複雜性而來的是強大的功能(和靈活性),因此表面上“過於複雜的”J2EE 規範及其關聯技術變得更為合適。
例如,門戶通常就屬於此類別,這是因為它們通常需要在所有三個層實現多重性 — 對於展示層,體現在門戶通常組合了公司各個部分(或部門,或不同的公司,甚至可能是不同的移動家庭)的不同 web 應用程式,對於商務邏輯層,體現在特定“portlet”有時將需要調用由不同的 portlet 的後端提供的功能,對於資料訪問層,體現在大多數 portlet 擁有自身的用於互動的資料庫(或資料庫集,目的是使事物更有意義),但更有趣的是,給定使用者的會話通常需要跟蹤進程中的資訊,即使使用者在各種 portlet 之間來回移動。在許多方面,門戶及其關聯 portlet 是公司專屬應用程式程式的典範。
“在許多方面,門戶及其關聯 portlet 是公司專屬應用程式程式的典範。”
它將我們至於何處?
此類分類本身就足夠出色了,因此會讓技術哲人們陶醉好一段時間,但這究竟與構建如今的企業 Java 應用程式有多大關係呢?
首先也是最重要的是,企業 Java 開發人員必須儘快確定他們被要求構建的應用程式屬於以上五種應用程式的哪一種。如果是傳統的煙囪系統,則選擇哪種技術並不像其他四個應用程式那樣重要。當出現 Web 服務問題時,將其看作是其他展示層(意味著您現在在查看珠寶應用程式)而不僅僅看作是 Struts 代碼與商務邏輯之間使用的模型對象擴充。實際上,在很多方面,模型視圖控制器模式是展示層本身的一部分,而並不是延伸到商務邏輯層的什麼東西,這是因為執行有效“不同”展示層通常將要求我們針對如何與後端互動進行不同的選擇,如(對於 Web 服務)將系統的“物件導向”的本質拋在後面。
當出現多個資料庫或其他後端問題時,請考慮故障可分性和使用分散式交易實現可分性的需要,以及擁有一個良好的間接可熱交換層來訪問資源的故障切換建議。當現有系統之間的整合成為問題時,請記住除 Web 服務以外還有很多選擇(儘管 Web 服務方法比較實用並且通常被看作是標準),並記住訊息驅動的系統以及是否可以將商務邏輯置於資料庫本身中以便其他需要與該系統互動的平台更容易地訪問此資料庫。
請記住,J2EE 只是用於實現某個目標的方法,對於任何技術的武斷看法通常將失去技術作為總體的意義。例如,不要試圖在煙囪系統上使用 EJB,這是因為 EJB 主要適用於交易處理(尤其是兩個階段的提交交易處理,此種交易處理比較佔用資源並且必須在作為同一事務一部分的兩個或更多資源中擷取可分性),但當彙總器應用程式依靠您執行操作時不要忽略它的使用。當 JMS(和訊息驅動 bean,當需要交易處理時)的非同步本質更適合於此目的時,不要嘗試將所有內容編寫為會話 bean。等等。
其次,一定要始終確切地牢記應用程式的效能和延展性目標(參見我的《高效企業 Java》一書)。儘管這對於以任何語言編寫的任何應用程式通常都很重要,但在企業 Java 領域中更重要,這是因為企業 Java 開發人員有那麼多的技術可以選擇。您的系統需要為每個使用者操作提供亞秒級響應?基於瀏覽器的應用程式(尤其是跨廣域網路應用程式)很難實現此目標,這是因為 HTML 瀏覽器通常需要大約一秒的時間來處理甚至是中等複雜的 HTML 頁;或許一個更好的方法是考慮通過 JavaWebStart 提交的“富用戶端”前端,以便使跨網路傳送的資料數量儘可能得小,以及接收資料的時間儘可能得短(以避免分析表示元素)。
是否需要在整個互連網上擁有預測的 100 萬個使用者?使用者介面肯定需要改變,而 Java 在普通使用者的 PC 上的低普及率使 WebStart 並不切合實際,或許 applet 或傳統的 HTML 更為合適。但擴充到此使用者數目意味著開發人員需要特別留意在高峰負載下每個請求的回應時間,或許以不同的方式構建使用者介面可以避免頻繁的伺服器回程。等等。
第三,請記住,Java 開發人員的工具套件在不斷的改進,過去五年中的大部分工作一直在朝 J2EE 領域的方向進行,想方設法使定義 J2EE 組件更簡單、更容易。大型商業供應商在該領域的優勢超過開源項目,這是因為供應商可以圍繞他們的商務服務建立完整的端到端開發經曆,其中開放源項目只是淺嘗輒止。例如,將 Oracle ADF 中提供的某些新功能與嘗試在 Eclipse 中構建 JSF 應用程式進行比較。或者,將在 JDeveloper 中定義 Web 服務與在 Axis 編寫 .wsdd 檔案進行對比。工具越來越完善,我們只能期望此趨勢得以繼續,因為這要看供應商有沒有興趣使其繼續了。 “工具越來越完善,我們只能期望此趨勢得以繼續,因為這要看供應商有沒有興趣使其繼續了。”
最後但並非不重要的,在本系列的後續文章中留意此技術領域,這些後續文章將介紹從建模和設計到調試以最佳化/監視代碼(這將比您現在定義的效能和延展性目標簡單很多)等主題。
最重要的是要放鬆。生命太短暫了。
結論
儘管企業 Java 領域有時像一組令人眼花繚亂的規範、實現,而實際上似乎迎合短暫流行風格的各種標準和架構已經做好充分的準備並意識到,對於五種類型的應用程式的任何一種而言,任何可用的 Java/J2EE 技術都可以工作(並出色地工作)。