0

我正在尝试在 Google App Engine (GAE) 的 servlet 中使用 Java Google Drive API,并在 Eclipse 的 (localhost) 服务器中首次加载 servlet 时获得NoClassDefFoundError 。

作为测试,我尝试在我的 servlet 中创建 GoogleClientSecrets 类的实例。Eclipse 编译器不抱怨,我在 Java 构建路径 google-api-client-1.16.0- 中有 C:\app\gDrive\libs**google-api-client-1.16.0-rc.jar** rc.jar 包含com.google.api.client.googleapis.auth.oauth2包,其中包含GoogleClientSecrets

Eclipse 中的 Google 插件中的 (localhost) 服务器照常加载。当我第一次加载 servlet 类时(当第一次请求它时),我得到 NoClassDefFoundError。如果我注释掉对 GoogleClientSecrets 的引用,则 servlet 工作正常。

google-api-client-1.16.0-rc.jar作为外部 jar 文件位于 Eclipse -> Java Build Path -> Libraries 列表中。它在 Order and Export 选项卡中标记为“检查”(我认为这意味着 jar 文件应该打包在 war 文件中——服务器环境应该可以使用它。

在运行时在 GAE 中使用这些类是否有一些限制?服务器或 servlet 的类加载器的类路径有什么不同吗?(在独立的 Java 应用程序中,代码可以正常访问 Google Drive(即,我在该 Java 应用程序环境中拥有所有需要的 jars——服务器中有些奇怪的东西(我认为那是 Jetty 服务器)。


更新DevAppServer 如何查找类

(正如 Mark Doyle 指出的那样)DevAppServer 的类加载方案对于加载 webapp 使用的类与用于加载 DevAppServer 代码本身的类加载方案完全不同——而且 web 应用程序类加载方案不是通常的 Eclipse 项目构建路径过程。(为了清楚起见,我在这里记录了所有这些是如何工作的,所以我可以再次找到它。)

研究一下,我看到在为 webapp 加载类时,DevAppServer 调用 Google 类“ IsolatedAppClassLoader ”(以将每个 webapp 的类加载相互隔离。IsolatedAppClassLoader.loadClass() 调用DevAppServerClassLoader .loadClass(),其中(在大多数情况下) case) 最终调用它的超类 java.lang.ClassLoader.loadClass(),在这种情况下调用 java.net.URLClassLoader.findClass(),后者调用 URLClassPath.getResource(),这是大部分工作的开始。

URLClassPath.getResource() 有一个“for”循环,它获取 URLClassPath 对象中列出的每个加载程序。在这种情况下,URLClassPath 中有 17 个(!十七个)加载器,所有 sun.misc.URLClassPath$JarLoader 的实例(URLClassPath 的子类)。- 这些似乎是 DevAppServer 罐子。找不到我的课程,返回 ClassNotFoundException(在此级别)。

IsolatedAppClassLoader再次这样做(我不明白为什么,但这次直接使用 URLClassLoader 对象(run() 方法),关于 PrivilegedExceptionAction.run()??))无论如何,URLClassPath(来自URLClassLoader ??) 运行 URLClassPath.getResource(),(这个 IsolatedAppClassLoader 实例是 URLClassLoader 的子类!)。IsolatedAppClassLoader 实例包含一个带有 21 个加载器的“ucp”字段(URLClassPath 子对象)。

第一个是一个 FileLoader 实例(URLClassPath 的子类),其中包含 url 文件:/C:/eclip/webAppName/war/WEB-INF/classes/——所以这是它在 war/WEB 中找到所有单个类的地方-INF/类目录。剩下的 20 个加载器都是 JarLoader 加载器。其中 15 个对应于项目的 war/WEB-INF 目录中的 15 个 .jar 文件。剩下的 5 个 JarLoader 实例是:

文件:/C:/app/eclipse/plugins/com.google.appengine.eclipse.sdkbundle_1.8.2/appengine-java-sdk-1.8.2/lib/impl/agent/appengine-agentruntime.jar!/文件:/ C:/app/eclipse/plugins/com.google.appengine.eclipse.sdkbundle_1.8.2/appengine-java-sdk-1.8.2/lib/tools/jsp/repackaged-appengine-jakarta-jstl-1.1.2.jar !/ file:/C:/app/eclipse/plugins/com.google.appengine.eclipse.sdkbundle_1.8.2/appengine-java-sdk-1.8.2/lib/tools/jsp/repackaged-appengine-jakarta-standard- 1.1.2.jar!/file:/C:/app/eclipse/plugins/com.google.appengine.eclipse.sdkbundle_1.8.2/appengine-java-sdk-1.8.2/lib/tools/jsp/repackaged-appengine -jasper-jdt-6.0.29.jar!/file:/C:/app/eclipse/plugins/com.google.appengine.eclipse.sdkbundle_1.8.2/appengine-java-sdk-1.8.2/lib/opt/工具/appengine-local-endpoints/v1/appengine-local-endpoints.jar!/

我不知道为什么这些都在列表中,可能是 Jetty 的一些标准东西?

4

1 回答 1

1

GAE 开发服务器 (Jetty) 设置了它自己的类路径,它不会关注您在 Eclipse 的构建路径中配置的内容。该类路径包括 WEB-INF/lib,因此您需要确保您要使用的任何库都位于那里,类似地,您项目中的类通常构建到 WEB-INF/classes。它还包括模拟生产环境所需的 GAE 库和依赖项。

另外GAE开发环境也提供了自己的类加载机制。这提供了对 GAE 库的访问,并且还实现了对可以访问哪些类的限制,这模仿了生产环境。例如,许多 Java IO/图形类受到限制,无法使用。

关于导出和打包到战争文件。如果您使用 Eclipse 的 WTP 进行 Web 开发,GAE SDK 的工作方式可能不会像您期望的那样工作。启动时它只是启动它的自定义 Jetty 实例并指向 web 文件夹。因此,如果您没有将 jar 库放在 WEB-INF/lib 中(类似地,如果您的类没有编译为 WEB-INF/classes),那么它们将不会被找到。

于 2013-08-18T11:33:54.957 回答