【发布时间】:2013-08-19 08:07:30
【问题描述】:
我正在尝试在 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 在 Eclipse -> Java Build Path -> 库列表中作为外部 jar 文件。它在 Order and Export 选项卡中标记为“检查”(我认为这意味着 jar 文件应该打包在 war 文件中——服务器环境应该可以使用它。
在运行时在 GAE 中使用这些类是否有一些限制?服务器或 servlet 的类加载器的类路径有什么不同吗? (在一个独立的 Java 应用程序中,代码可以很好地访问 Google Drive(即,我在那个 Java 应用程序环境中拥有所有需要的 jars ——服务器中有一些奇怪的东西(我认为那是 Jetty 服务器)。
更新DevAppServer如何查找类
(正如 Mark Doyle 所指出的)DevAppServer 的类加载方案对于加载 webapp 使用的类与用于加载 DevAppServer 代码本身的类加载方案完全不同——而且 web app 类加载方案不是通常的Eclipse 项目构建路径过程。 (为了清楚起见,我在这里记录了所有这些是如何工作的,以便我可以再次找到它。)
调查后我发现,在为 webapp 加载类时,DevAppServer 调用 Google 类“IsolatedAppClassLoader”(以隔离每个 webapp 的类加载。IsolatedAppClassLoader.loadClass() 调用DevAppServerClassLoader.loadClass(),(在大多数情况下)最终调用其超类 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/classes 目录中。剩下的 20 个加载器都是 JarLoader 加载器。其中 15 个对应于项目的 war/WEB-INF 目录中的 15 个 .jar 文件。剩下的 5 个 JarLoader 实例是:
file:/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!/ 文件:/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!/ 文件:/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!/ 文件:/C:/app/eclipse/plugins/com.google.appengine.eclipse.sdkbundle_1.8.2/appengine-java-sdk-1.8.2/lib/opt/tools/appengine-local-endpoints/v1/appengine- local-endpoints.jar!/
我不知道为什么这些都在列表中,可能是 Jetty 的一些标准东西?
【问题讨论】:
-
我只是将它添加到 LIB 文件夹而不是假设 eclipse 复选标记会这样做。