在 SpringSource dm Server 中部署 GWT 應用程式 - 第 2 部分

工程 | Ben Corrie | 2008 年 11 月 24 日 | ...

介紹

這是由三部分組成的系列部落格中的第二篇,描述了在 SpringSource dm Server™ 中構建和部署 GWT 應用程式的分步方法。第一篇部落格著眼於如何從一個 GWT 示例應用程式建立一個簡單的 WAR 檔案。下一篇部落格將探討如何將我們在第 1 部分中建立的 WAR 檔案轉換為一個“共享庫” WAR。這意味著我們將把應用程式的 GWT 依賴項外部化到一個 OSGi Bundle 中,以便它可以被任意數量的 GWT 應用程式共享。您可以將其視為使用 GWT 遠端處理功能擴充套件了我們的 dm Server。

正如在第 1 部分中提到的,我在這篇部落格中不使用Spring Framework,而是專注於 SpringSource dm Server™SpringSource Tool Suite 來部署“純粹的” GWT。

請參閱第 1 部分瞭解 GWT StockWatcher 示例的背景以及我使用的軟體。

快速回顧

第 1 部分中,我們從頭開始將 GWT StockWatcher 示例應用程式構建為一個 Eclipse 專案,然後將程式碼生成到一個動態 Web 專案中,並將其部署到 dm Server。最後,我們將動態 Web 專案匯出為一個 WAR 檔案,並在 STS 外部進行部署。

此處描述的分步方法將基於我們在第 1 部分中完成的工作,而不是從頭開始。我們在第 1 部分中現在要更改的唯一一件事是刪除對以下庫的顯式依賴:gwt-servlet.jar庫。

步驟 1:將我們的 GWT 依賴項轉換為 OSGi Bundle

首先,再補充一點背景。“共享庫”方法的整體概念是利用 OSGi Bundle 之間的顯式匯入和匯出,在 dm Server 內部建立一個依賴項對映。對於像我們的 StockWatcher 示例這樣的小型 WAR,這主要只是一項有趣的學術實踐。然而,考慮到許多商業 Web 專案以大型 WAR 檔案形式釋出,其中打包了數十甚至數百個依賴的 Jar 檔案,將這些依賴項分解為可共享資源不僅從空間佔用角度來看有意義,而且還顯著減輕了應用程式的打包、版本控制和維護的痛苦。

好訊息是,建立這些依賴項的大部分工作已經有人為您完成了。SpringSource Enterprise Bundle Repository 包含了大多數常用庫的“打包”版本。然而,在撰寫本文時,我們的 GWT 依賴項是一個需要您自己將其轉換為 Bundle 的庫示例。幸運的是,Eclipse 3.4 使這個過程非常簡單。

- 在“專案資源管理器”中右鍵單擊,選擇“新建”->“其他”->“外掛開發”->“從現有 Jar 歸檔檔案建立外掛”。- 點選“新增外部”,然後瀏覽找到gwt-servlet.jar。- 點選“下一步”,並將專案命名為“com.google.gwt”。- 設定外掛版本以反映 GWT 版本,在本例中是 1.5.3。- 選擇“分析庫內容並新增依賴項” - 選擇 Equinox OSGi 框架

點選“完成”,無需切換到外掛開發透檢視。我們只是要直接將我們的 Bundle 再次匯出。

您現在應該會看到生成的MANIFEST.MF檔案,其中定義了 Bundle 的依賴項。您將在“執行時”選項卡中看到該工具已添加了所有com.google.gwt..包作為匯出。您還將在“依賴項”選項卡中看到它已經識別出此 Bundle 需要一些javax.servlet..包以及一個junit包。

我們現在將移除 JUnit 依賴項,因為它在 dm Server 中預設將無法解析。當然,如果我們願意,我們可以向 dm Server 新增一個 JUnit Bundle 來滿足此依賴項,或者,我們可以透過新增以下內容使該依賴項成為可選的:required:=optional。選擇junit.framework包,點選“移除”,然後儲存。

值得指出的是,這是一種將 JAR 檔案轉換為 Bundle 的粗略方法,不能保證在所有情況下都能奏效。一方面,我們可能不想匯出所有包。更重要的是,有一些原始碼級別的陷阱可能在 OSGi 中表現不佳,例如使用Class.forName()。如有疑問,請務必首先檢視 SpringSource Enterprise Bundle Repository,而不是嘗試自己建立。

最後,我們需要將我們的外掛專案匯出為一個 OSGi Bundle。選擇“匯出”->“外掛開發”->“可部署外掛和片段”。選擇一個方便的位置作為輸出目錄。

我們現在應該會在以下路徑看到一個檔案:<export path>/plugins/com.google.gwt_1.5.3.jar。下一步是將檔案重新命名,使其與 dm Server 中其他命名 Bundle 的格式一致:只需將下劃線更改為破折號com.google.gwt-1.5.3.jar。如果不進行此更改,當前版本的 STS 將無法識別 Bundle 版本。如果您想跳過此步驟,可以從此處下載。

最後,將 Bundle 複製到 dm Server 的 Bundle 倉庫中:<dm Server installation root>/repository/bundles/usr。這裡的任何 Bundle 都可以成為 dm Server 中其他 Bundle 的依賴項,但重要的是它在 STS 中也將作為依賴項可見,正如我們在下一步中將看到的。

此時,您可以從工作區中刪除 com.google.gwt 專案,因為它已經完成了它的使命。

步驟 2:將我們的 WAR 專案遷移到新的 OSGi Bundle

希望您現在已經有一個 dm Server 安裝,並且其倉庫中包含一個com.google.gwt-1.5.3.jar

下一步是“破壞”我們的應用程式!

右鍵單擊 StockWatcherWar,選擇“屬性”->“Java EE 模組依賴項”,取消選中gwt-server.jar檔案,然後點選“確定”。我們現在已經刪除了 WAR 對 GWT 的顯式依賴,給自己造成了許多新問題,其中大多數是編譯器錯誤。

所以我們需要將我們的動態 Web 專案轉換為一個 dm Server Bundle,以便它可以從我們新建立的 GWT Bundle 中顯式匯入所需的依賴項。為此,右鍵單擊 StockWatcherWar,選擇“Spring Tools”->“新增 OSGi Bundle 專案特性”。您應該注意到該專案現在帶有一個非常重要的“S”符號,並且MANIFEST.MF也改變了字元。

它現在處於破損狀態,因為它看起來不像一個 Bundle 清單。讓我們新增一些合理的預設值(您可以複製貼上以下內容,或使用選項卡中的欄位)。請注意,您也可以在編輯器中使用 ctrl-space 來提示您有效的選項。

Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: com.google.sample.stockwatcher Bundle-SymbolicName: com.google.sample.stockwatcher Bundle-Version: 1.0.0 Bundle-Description: Shared Libraries StockWatcher demo

這樣就解決了一個問題,我們的 Bundle 清單現在看起來正常了。然而,我們尚未定義對 GWT Bundle 的依賴,所以我們仍然有一些編譯器錯誤。

選擇“依賴項”選項卡並點選“新增”。在頂部,您應該會看到一個 com.google.gwt Bundle 神奇地出現了。現在,重要的是要明白,此列表中出現的 GWT Bundle 與我們在步驟 1 中建立的外掛專案無關。如果您從工作區中刪除該專案,該 Bundle 仍然會出現在列表中。這是因為 dm Server 安裝被設定為專案的執行時環境,因此工具會在 dm Server 的倉庫中查詢您可能想要匯入的任何 Bundle。如果這一步沒有成功,則說明 GWT Bundle 沒有被複制到正確的位置,或者 WAR 專案的執行時環境沒有設定為 dm Server。請在“屬性”->“目標執行時”中檢查後者。

接下來,選擇 GWT Bundle,點選“確定”,然後儲存清單。您現在應該會看到 GWT Bundle 被新增到一個名為“Bundle Dependencies”的新類路徑元素中。

您現在應該注意到大多數錯誤已經解決,但仍有幾個未解決。這是因為我們的 GWT Bundle 依賴於javax.servletAPI,並且在我們獲得這些類之前,型別層次結構是不完整的。

那麼,為什麼當我們之前只有gwt-servlet.jar在我們的構建路徑中時,沒有遇到這個問題呢?嗯,在我們進行更改之前,我們的 WAR 會拾取其構建路徑上的所有內容,其中包括 dm Server 目標執行時提供的所有 JAR。然而,您可能已經注意到,當我們新增 OSGi Bundle 專案特性時,構建路徑上的 dm Server JAR 檔案消失了。這是因為,透過成為 OSGi Bundle,我們進入了一個不同的依賴關係世界,在這個世界裡,匯入和匯出必須顯式宣告。

宣告我們對javax.servletAPI 的依賴項很簡單,只需匯入另一個 Bundle。您將在列表中看到它,名稱為com.springsource.javax.servlet。新增這兩個 Bundle 後,儲存清單,您現在應該會看到所有錯誤都已解決。太好了!

如果我們現在導航到 MANIFEST.MF 選項卡,我們可以看到我們所有點選操作的效果:清單中有一個綠色的“Import-Bundle”條目。請注意,我們也可以在“Import-Bundle”後面輕鬆使用 ctrl-space,它會建議所有可能的匯入。

如果您想檢視我的專案,可以從此處下載一個壓縮副本。它包括在嵌入式 Tomcat 中以 hosted mode 啟動、在 dm Server 中以 hosted mode 啟動以及啟動 GWT 編譯器的執行時配置。請注意,使用嵌入式 Tomcat 的 hosted mode 可以正常工作,無需修改 Bundle WAR 專案。這是因為javax.servlet從 dm Server 獲得的包不再位於構建路徑中。要使用我的專案,您需要設定GWT_ROOT_INSTALL變數,並且您可能需要選擇您的 dm Server 目標執行時例項,如第 1 部分中所述。

步驟 3:部署到 dm Server

部署我們的“共享庫”應用程式的步驟與第 1 部分中的步驟 7 和 8 完全相同,因此沒有必要再次詳細介紹。當然,關鍵區別在於我們已成功地將依賴項分解為一個可以由多個 GWT 應用程式共享的庫。如果您下載我的StockWatcher 共享庫 WAR,您會看到它現在只有 290k,而不是 890k。

為了好玩,讓我們看看幕後,瞧瞧我們的 Bundle 是如何互動的。

dm Server 啟動時,會通知您其 OSGi 控制檯可以透過 telnet 客戶端訪問:

[2008-10-27 16:48:04.266] main                     <SPOF0001I> OSGi telnet console available on port 2401.

讓我們開啟一個終端視窗,看看能發現什麼:

> telnet localhost 2401 Trying ::1... Connected to localhost. Escape character is '^]'.

osgi>

您可以透過輸入 help 來獲取 Equinox 控制檯可用的命令列表。還有一篇有用的 DeveloperWorks 文章,您可以在此處閱讀。

輸入ss可以列出所有正在執行的外掛:

osgi> ss

Framework is launched.

id    State       Bundle . . . . 73    ACTIVE      com.google.sample.stockwatcher_1.0.0 74    ACTIVE      com.google.gwt_1.5.3

輸入packages 74可以列出 GWT Bundle 中所有匯出的包。它顯示所有匯出的包都被 StockWatcherWar Bundle 匯入。這是我們使用“Import-Bundle”的結果。實際上,我們的 StockWatcherWar 唯一需要的包是com.google.gwt.user.client.rpccom.google.gwt.user.server.rpc。如果我們願意,我們可以改用“Import-Package”更具選擇性地顯式匯入這些包。這在dm Server 程式設計指南中有所描述。

file:////Users/bcorrie/dmServer-1.0.0/springsource-dm-server-1.0.0.RELEASE/work/com.springsource.server.deployer/Module/StockWatcherWar.war-0/StockWatcherWar.war [73] imports com.google.gwt.i18n.client.constants; version="0.0.0"<file:////Users/bcorrie/dmServer-1.0.0/springsource-dm-server-1.0.0.RELEASE/repository/bundles/usr/com.google.gwt-1.5.3.jar [74]>

步驟 4:在共享庫上部署其他 GWT 應用程式

值得注意的是,並非所有 GWT 應用程式都需要使用gwt-servlet.jar。只有使用某種形式的遠端處理的 GWT 應用程式才依賴於此庫。Google 在其發行版中附帶了許多示例應用程式,其中大多數僅生成 javascript 和 html,因此部署時沒有 Java 程式碼。將這些示例轉換為 WAR 檔案很簡單,只需按照第 1 部分步驟 5 所述,將編譯指令碼執行到動態 Web 專案中,然後建立一個合適的 web.xml 即可。

然而,GWT 發行版中包含的一個確實使用了簡單遠端處理的示例叫做 DynaTable。我使用這些部落格中描述的相同步驟和原理,將此示例轉換為一個共享庫 WAR 檔案。要了解我是如何做的,您可以下載壓縮後的專案WAR 檔案檢視。這非常簡單地演示了在 dm Server 中執行多個應用程式的原則,所有這些應用程式都共享我們建立的 GWT Bundle。

展望第 3 部分

在本系列的最後一篇部落格中,我們將進一步模組化我們的 StockWatcher 示例,將其服務抽象為可以熱插拔進出執行伺服器的 Bundle。

訂閱 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速發展。

瞭解更多

獲取支援

Tanzu Spring 透過一個簡單的訂閱提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視全部