【问题标题】:Converting a simple AppEngine Java project to use modules将简单的 AppEngine Java 项目转换为使用模块
【发布时间】:2015-12-09 16:40:58
【问题描述】:

这个问题类似于this one,但这并没有解决我的问题。

我有一个非常简单的 Google AppEngine / Java 应用程序。它自 2011 年以来一直在运行,并且不使用 maven 或其他我认为不需要的花哨的东西。最近,我向此应用程序添加了 Cloud Endpoints。我没有使用生成的endpoint-libs,因为我似乎不需要它,没有它一切正常。

应用程序拥有前端和后端已有一段时间了。我现在正在尝试将这些转换为模块:前端将成为默认模块,后端将成为另一个模块。

我的旧项目的结构是这样的:

project
 |- src
 |   |- ... Java source files ...
 |
 |- war
 |   |- WEB-INF
 |   |   |- appengine.xml
 |   |   |- backends.xml
 |   |   |- cron.xml
 |   |   |- web.xml

我通过为 Java 类提供正确的注释来实现云端点。没有花哨的 maven 生成魔法。

我了解我需要为每个模块创建一个目录,如下所示:

project
 |- default
 |   |- WEB-INF
 |   |   |- appengine.xml
 |   |   |- cron.xml
 |   |   |- web.xml
 |
 |- module
 |   |- WEB-INF
 |   |   |- appengine.xml
 |   |   |- web.xml
 |
 |- META-INF
 |   |- appengine-application.xml
 |   |- application.xml

我的问题是:

  • 我应该把src 目录放在哪里?
  • 我应该在default/WEB-INF/web.xml 中声明我的云端点类吗?
  • 每个模块可以有自己的WEB-INF/cron.xml吗?

如果看起来我不知道自己在做什么,那可能是对的,但我不想将所有内容都放在 maven pom 文件中,编写 gradle 脚本等,并专注于实际应用程序。这可能是因为我在 vi 和 emacs 的陪伴下长大,那时我们自己编写代码。 ;)

更新:

我把src目录放在project下,和defaultmodule同级。编译后的 Java 类出现在default/WEB-INF/classes 下,这表明我做对了。 GAE 在default/WEB-INF 中生成了一个*.api 文件,这是我之前不使用模块时没有看到的。

在本地,我可以看到我的云端点 API,我可以使用它们。当我部署到 AppEngine 并尝试使用 API 资源管理器时,出现异常:

/_ah/spi/BackendService.getApiConfigs java.lang.NullPointerException 在 com.google.api.server.spi.SystemServiceServlet.execute(SystemServiceServlet.java:100) 在 com.google.api.server.spi.SystemServiceServlet。 doPost(SystemServiceServlet.java:71) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:637) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

等等……

我确实添加了 OAuth2 凭据并将它们设置在我的云端点配置中。 我找不到SystemServiceServlet 的代码,但我猜它找不到我的API 类(在default/WEB-INF/web.xml 中配置)。

另一个更新:

我了解到 AppEngine 模块需要企业存档 (ear) 结构,并且像简单的 GAE 应用程序那样进行部署是行不通的。 没有“一键式”部署。 我按照Programming Google App Engine with Java 中的说明操作,最终得到了一堆 Eclipse 项目。它是enterprisey,但我可以让它抛出与我之前部署的简单版本相同的异常。 我不知道我是否取得了任何进展。

【问题讨论】:

  • 顺便说一句,maven!= 代码生成工具(或类似的东西)。它就像一个makefile(用于您编写的代码)。是的,2015 年 Maven 太陈旧了,不要使用它 :)
  • @Igor Artamonov 是的 makefile,我很怀念它们。我会称之为 maven 巴洛克风格。谷歌在他们的 appengine 文档中经常使用它,所以它不会是过时的吗? ;)

标签: java google-app-engine google-cloud-endpoints gae-module app-engine-modules


【解决方案1】:

我创建了 Appstart (https://github.com/omerio/appstart) 一个基于样板 maven 的多模块 App Engine 应用程序,该应用程序演示了包括 Cloud Endpoints 在内的一些技术的使用,并具有 3 个模块:前端模块、后端模块和通用模块,其中包括所有模块之间共享的公共类。

项目设置在父文件夹“appstart”中,并带有父 maven POM。您可以轻松地签出项目,删除不需要的内容,添加代码,您应该拥有一个多模块项目。或者,您可以构建类似于 appstart 的代码。在这种情况下,您需要执行以下操作:

  • 在您的项目文件夹中添加一个带有 <packaging>pom</packaging> 的父 pom 并将您的模块添加到其中(以 appstart parent pom 为例)。
  • 您的每个模块都包含一个 pom,该 pom 具有父元素 <parent>(请参阅 appstart-frontend pom 作为示例)。
  • 您需要创建一个带有耳包(Enterprise ARchive)的项目,这有助于一次性部署所有模块(参见appstart-ear as an example

您的 Cloud Endpoints 可以像 appstart's web.xml 一样在您的 default/WEB-INF/web.xml 中声明。

appstart-frontend 中还包含一个示例 cron.xml。 cron.xml 文件必须添加到App Engine docs 中提到的默认模块。要在模块上调用 cron 作业,只需在 cron.xml 中包含 <target>my-module</target> 元素。

【讨论】:

  • 我做了一个小改动,cron.xml 需要包含在默认模块的 WEB-INF 中,如此处提到的cloud.google.com/appengine/docs/java/modules/… 使用 cron.xml 中的目标元素来定位特定模块。
  • 谢谢奥梅里奥。出于某种奇怪的原因,我对专家过敏,我尽量避免它。你的一些言论在没有 maven 的情况下很有用,我会试试这个(没有 maven)。现在提到足够多的 maven,我能感觉到我的血压在上升。 ;)
  • @rakensi 如果不想使用 maven 而您确实使用 Eclipse,您可以为您的模块创建一个 EAR 项目,然后使用 Eclipse 或 appcfg 来部署您的模块。更多信息在这里:cloud.google.com/appengine/docs/java/… 和这里:cloud.google.com/appengine/docs/java/modules/…
  • 再次感谢奥梅里奥。我这样做了,所以我的项目看起来与那些文档所描述的完全一样。但是现在云端点不会部署,因为 /_ah/spi/BackendService.getApiConfigs 中的 NullPointerException。显然,它找不到我的 Java 类,因为它们不在默认模块中。现在我回到我最初的问题,如何构建我的项目(不使用 maven)。
  • @rakensi 我认为你的结构是正确的,它只是让端点编译,你使用 eclipse 吗?,这个答案可能会帮助stackoverflow.com/questions/26340444/…
【解决方案2】:

虽然文档强烈建议您需要耳朵来执行此操作,但您不需要。 您只需在 appengine-web.xml 中添加一个模块定义,您的战争就会部署到指定的模块。默认模块:

<module>default</module>

对于后端

<module>backend</module>
<manual-scaling> ... </manual-scaling>

这具有在默认模块和其他模块上使用相同代码的好处,但需要在部署时以某种方式切换它(无需磨牙更多我使用 maven 配置文件),您可以只拥有另一个分支或手动执行.那么你应该可以正常部署了,但是你需要做两次。

这是我见过的最简单的迁移路径,如果你已经打过仗,设置耳朵会很痛苦。

【讨论】:

  • 谢谢,尼克。如果我理解正确,如果您使用不同的模块名称两次部署到同一个 AppEngine 项目,您最终将在项目中使用两个模块。这意味着我可以有两个单独的 Eclipse 项目,它们指向同一个 AppEngine 项目,并获得两个模块。我将无法使用相同的代码。我假设这两个模块使用相同的数据存储,这开辟了一些有趣的可能性。
  • 对,或者如果您使用相同的代码库并部署两次,它将与后端相同。
【解决方案3】:

最终,我严格按照Programming Google App Engine with Java(第 5 章)中给出的说明,逐步添加了我的旧代码。这行得通,我没有再得到空指针异常(不知道是什么原因造成的)。

需要注意的几点:

  • 模块不共享代码。在 Eclipse 中,您可以在一个项目中创建指向另一个项目中源文件夹的链接。这是我能找到的共享代码的最佳方式。
  • 您必须在 Eclipse 中使用 Java EE 透视图。这有一个“服务器”选项卡,其中包括一个带有“部署到远程服务器”菜单条目的 GAE 按钮。这是部署模块的方式。 “Google / Deploy to AppEngine”上下文菜单条目不适用于模块/企业项目。
  • cron.xml 和 datastore-indexes.xml 等特殊文件必须位于“默认”模块的 WEB-INF 目录中。
  • Google 服务器上的Routing URLs to modules 与开发服务器有很大不同。
  • 在开发服务器上,本地数据存储隐藏在 Eclipse 目录的某个位置。通过服务器配置中的changing the working directory 修复此问题:双击服务器。这将打开一个“服务器编辑器”。填写附加虚拟机参数:-Ddatastore.backing_store=/C:/wherever/local_db.bin

我的项目的目录结构现在如下所示:

project
 |- default
 |   |- src
 |   |- WebContent
 |   |   |- WEB-INF
 |   |   |   |- appengine.xml
 |   |   |   |- cron.xml
 |   |   |   |- web.xml
 |
 |- module
 |   |- WebContent
 |   |   |- <HTML, CSS etcetera>
 |   |   |- WEB-INF
 |   |   |   |- appengine.xml
 |   |   |   |- web.xml
 |
 |- ear     (the EAR project)
 |   |- EarContent
 |   |   |- META-INF
 |   |   |   |- appengine-application.xml
 |   |   |   |- application.xml

其中大部分是按照上述书中的说明生成的。

我希望这将有助于其他人努力使他们的 AppEngine 项目模块化。

【讨论】:

    猜你喜欢
    • 2010-11-15
    • 2011-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 2012-09-21
    • 1970-01-01
    相关资源
    最近更新 更多