自Google的Java Java引擎启动以来,我一直试图创建一个小型但具有代表性的项目,并将其部署在Google的基础架构上。 我学到了很多东西,主要是犯了错误。 有趣的是,我取得了很多我不希望自己取得的成就。 相反,正如他们所说,魔鬼是细节,我发现那里是我无法想象的问题:对于某些问题,还有其他解决方案,对于某些问题则没有。
日食
Eclipse是我的第一个也是最重要的IDE。 我尝试过NetBeans,但是尽管我已通过NetBeans认证,但对我来说太奇怪了。 无论如何,Google为GAE提供了一个Eclipse插件。 当我尝试在更新站点上安装它时,出现了一个不太好的错误弹出窗口:
Cannot complete the install because one or more required items could not be found. Software being installed: com.google.gdt.eclipse.suite.e34.feature.feature.group 1.0.0.v200904062334 Missing requirement: com.google.gdt.eclipse.suite.e34.feature.feature.group 1.0.0.v200904062334 requires \ 'org.eclipse.platform.feature.group [3.4.0,3.5.0)' but it could not be found
Google的插件仅适用于3.4版(Ganymede),而我具有3.5版(Galileo)。 对于Eclipse来说已经这么久了,但是Google似乎计划不迟于Galileo自己的版本发布与Galileo兼容的版本(感谢Rajeev )。
马文
像每个不那么年轻的Java开发人员一样,我曾经精通过Ant。 但是我无聊为每个项目编写相同的任务,所以我让Maven勾引我。 看来Google的人仍然只使用Ant(GAE文档中没有对Maven的引用),因此如果要使用Maven,则必须执行以下操作:
- 参考DataNucleus存储库。 这是网址: http : //www.datanucleus.org/downloads/maven2 ,
- 将依赖项添加到:
-
org.datanucleus:datanucleus-core:1.1.0:jar
-
org.datanucleus:datanucleus-jpa:1.1.0:jar
, -
org.datanucleus:datanucleus-enhancer:1.1.0:jar
,
-
-
datanucleus-core
对javax.jta:transaction-api:1.1:jar
有依赖性。 由于其POM引用了本地存储库(!),因此不会找到此工件。 您必须使用该名称手动安装JTA 1.1, - 手动安装并将依赖项添加到:
-
org.datanucleus:datanucleus-appengine:1.0.0.final:jar
, -
com.google.appengine:appengine-api:1.0:jar
。
-
弹簧
在GAE中,Spring就像魅力一样。 GAE的文档说,反射已完全得到支持,因此这不足为奇。 我虽然没有使用AOP。
公共记录
Commons-logging是许多框架(包括Spring)的依赖项。 在本地服务器上,一切运行正常。 在云中,Google App Engine基础结构用其自身的JAR(具有不同的包结构)替换了commons-logging-1.1.1.jar。 实际上,这意味着即使您将JAR包含为依赖项,您也会在org.apache.commons.logging.LogFactory
上看到有趣的NoClassDefFoundError
。 解决方案是仍然包括类,但给JAR重命名。
由于我使用Maven,因此使用Spring和MyFaces工件的exclusion
标记从WAR中删除了commons-logging依赖性。 然后,我在运行时范围内添加了对commons-logging:commons-logging-api:1.1:jar
的依赖。 这个罐子不会被更换。
JSP
JSP在页面中可以正常工作。 但是,XML格式JSP似乎没有得到翻译。 您需要创建“经典” JSP。
不过,您可能会遇到一些有趣的例外。 它看起来像这样:
java.lang.ClassCastException: SomeException cannot be cast to javax.servlet.ServletException at org.apache.jasper.runtime.PageContextImpl.handlePageException(PageContextImpl.java:754) at org.apache.jsp.some_jsp._jspService(some_jsp.java:some_line)
似乎PageContextImpl
类中存在一个错误,其中任何RuntimeException
都将ServletException
为ServletException
,从而最终创建另一个异常。 这是非常困难的,因为ClassCastException
堆栈跟踪将隐藏第一个堆栈跟踪。 为了进行调试,我建议您在内接的JSP中使用以下代码段:
<%try{%>
...yourJSPbody...
<%}catch(RuntimeExceptione){
Loggerlog=Logger.getLogger(getClass().getName());
StringWritersw=newStringWriter();
e.printStackTrace(newPrintWriter(sw));
log.severe(sw.toString());
throwe;
}%>
EL
JSF标记(#)中的EL语法运行良好。 对于JSTL taglibs中的EL语法-例如核心($),一开始它不起作用。 多亏了Jim ,我知道您现在必须告诉App Engine不要在将EL与JSTL一起使用的每一页上使用代码<%@ page isELIgnored="false" %>
忽略它。 恕我直言,这可能是默认行为,例如在Tomcat中。
JSF
Apache MyFaces v1.1可以很好地工作。 我的1.2版有问题:显然,某个地方有API不匹配。 因此,我暂时仍旧使用旧版本。
JPA
GAE选择的持久性API是JDO 。 来吧,伙计们,2009年的JDO? 尽管如此,GAE仍然接受JPA作为替代的持久性API,因此您在使用它时要格外小心。 在这两种情况下,GAE都使用DataNucleus框架(我第一次听说它-它似乎与JDO JPOX团队有关)。 与任何JDO框架一样,此框架使用自定义字节码增强了您的实体类:这在编译后的构建过程中进行。 DataNucleus令人惊讶的是,即使您选择JPA作为持久性API,也必须增强实体类。
由于增强过程依赖于某些工件,因此请检查这些工件是否被引用为依赖项(请参见上面的列表)。 要将增强功能绑定到编译阶段,请在您的POM中使用以下代码段(感谢Andy ):
<build>
...
<plugin>
<groupId> org.datanucleus </groupId>
<artifactId> maven-datanucleus-plugin </artifactId>
<version> 1.1.0 </version>
<configuration>
<mappingIncludes> net/frankel/hr/cra/model/*.class </mappingIncludes>
<verbose> true </verbose>
<api> JPA </api>
</configuration>
<executions>
<execution>
<phase> compile </phase>
<goals>
<goal> enhance </goal>
</goals>
</execution>
</executions>
</plugin>
...
</build>
使用Datanucleus存在另一个限制,即如果使用JPA(或JDO)进行查询,则必须在结果List
上显式调用size()
方法。 否则,您的JSP将抛出一个不太好的NucleusUserException
标记为“对象管理器已关闭”。 在datanucleus-appengine集成项目中提出了一个问题 。
本地AppEngine服务器
本地服务器运行良好。 我不禁要问,为什么翻译/编译过程会花费这么多时间(以分钟为单位)。 完成后,页面渲染非常Swift,因为我认为服务器可以优化缓存。
部署应用程序
最初的appcfg.cmd
启动Java类。 我不知道为什么,但是应用程序只是忽略了JAVA_HOME
环境变量,并不断检查java.home
系统属性。 如果未找到后者,它将尝试使用C:\Program Files\Java\jre6\bin
和C:\Program Files\Java\bin
寻找javac
。 如果找不到,它将失败...我不得不修改appcfg.cmd来放置以下命令行:
java -Djava.home="%JAVA_HOME%" -cp "%~dp0\..\lib\appengine-tools-api.jar" com.google.appengine.tools.admin.AppCfg %*
无论如何,它无济于事,因为我收到以下SSL异常:
Unable to upload: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Unknown Source) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(Unknown Source) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source) at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Unknown Source) at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Unknown Source) at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(Unknown Source) at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Unknown Source) at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Unknown Source) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(Unknown Source) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source) at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(Unknown Source) at sun.net.www.protocol.https.HttpsClient.afterConnect(Unknown Source) at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(Unknown Source) at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(Unknown Source) at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(Unknown Source) at com.google.appengine.tools.admin.ServerConnection.connect(ServerConnection.java:295) at com.google.appengine.tools.admin.ServerConnection.getAuthToken(ServerConnection.java:215) at com.google.appengine.tools.admin.ServerConnection.authenticate(ServerConnection.java:189) at com.google.appengine.tools.admin.ServerConnection.send(ServerConnection.java:116) at com.google.appengine.tools.admin.ServerConnection.post(ServerConnection.java:66) at com.google.appengine.tools.admin.AppVersionUpload.send(AppVersionUpload.java:345) at com.google.appengine.tools.admin.AppVersionUpload.beginTransaction(AppVersionUpload.java:159) at com.google.appengine.tools.admin.AppVersionUpload.doUpload(AppVersionUpload.java:68) at com.google.appengine.tools.admin.AppAdminImpl.update(AppAdminImpl.java:41) at com.google.appengine.tools.admin.AppCfg$UpdateAction.execute(AppCfg.java:469) at com.google.appengine.tools.admin.AppCfg.(AppCfg.java:114) at com.google.appengine.tools.admin.AppCfg.main(AppCfg.java:59) Caused by: sun.security.validator.ValidatorException: No trusted certificate found at sun.security.validator.SimpleValidator.buildTrustedChain(Unknown Source) at sun.security.validator.SimpleValidator.engineValidate(Unknown Source) at sun.security.validator.Validator.validate(Unknown Source) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(Unknown Source) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source) ... 24 more
解决方案是使用JDK中捆绑的JRE。 命令行因此变为:
java -Djava.home="%JAVA_HOME%/jre" -cp "%~dp0\..\lib\appengine-tools-api.jar" com.google.appengine.tools.admin.AppCfg %*
现在一切都应该从这里完美运行。 玩得开心!