领先一步
VMware 提供培训和认证,助您加速发展。
了解更多正如在第 1 部分中提到的,我在这篇博客中不使用Spring Framework,而是专注于 SpringSource dm Server™ 和 SpringSource Tool Suite 来部署“纯粹的” GWT。
请参阅第 1 部分了解 GWT StockWatcher 示例的背景以及我使用的软件。
此处描述的分步方法将基于我们在第 1 部分中完成的工作,而不是从头开始。我们在第 1 部分中现在要更改的唯一一件事是删除对以下库的显式依赖:gwt-servlet.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 项目,因为它已经完成了它的使命。
下一步是“破坏”我们的应用程序!
右键单击 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 部分中所述。
为了好玩,让我们看看幕后,瞧瞧我们的 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.rpc和com.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]>
然而,GWT 发行版中包含的一个确实使用了简单远程处理的示例叫做 DynaTable。我使用这些博客中描述的相同步骤和原理,将此示例转换为一个共享库 WAR 文件。要了解我是如何做的,您可以下载压缩后的项目或WAR 文件查看。这非常简单地演示了在 dm Server 中运行多个应用程序的原则,所有这些应用程序都共享我们创建的 GWT Bundle。