【问题标题】:java.lang.NoClassDefFoundError for a jar file downloaded at run time运行时下载的 jar 文件的 java.lang.NoClassDefFoundError
【发布时间】:2012-03-12 01:44:17
【问题描述】:

我的 java 应用程序启动如下: /usr/java6_64/bin/java -cp main.jar:updater.jar:jtapi.jar

在某些情况下 jtapi.jar 不存在,而是在运行时下载。 main.jar 和 updater.jar 旨在解决这个问题。这可以在包括 AIX 5.3 在内的多个操作系统上完美运行。

但是,在 AIX 7.1 上,如果 jtapi.jar 一开始不存在,它就会失败。这是一个例外:

Exception in thread "main" java.lang.NoClassDefFoundError: com.cisco.jtapi.extensions.CiscoProviderObserver
        at java.lang.ClassLoader.defineClass(ClassLoader.java:275)
        at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:69)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:540)
        at java.net.URLClassLoader.defineClass(URLClassLoader.java:451)
        at java.net.URLClassLoader.access$300(URLClassLoader.java:79)
        at java.net.URLClassLoader$ClassFinder.run(URLClassLoader.java:1038)
        at java.security.AccessController.doPrivileged(AccessController.java:284)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:429)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:660)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:358)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:626)
        at com.genesyslab.ciscocm.JtapiUpdater.main(JtapiUpdater.java:107)
Caused by: java.lang.ClassNotFoundException: com.cisco.jtapi.extensions.CiscoProviderObserver
        at java.net.URLClassLoader.findClass(URLClassLoader.java:434)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:660)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:358)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:626)
        at java.lang.ClassLoader.defineClassImpl(Native Method)
        ... 12 more

之后立即再次运行它,它工作正常,因为 jtapi.jar 已经存在。 我已经验证 jtapi.jar 文件已经下载成功,甚至增加了延迟以确保它有时间。同样,这目前在早期版本的 AIX 和其他操作系统上运行良好。

有什么想法吗?

编辑: 到目前为止,“消除不存在的文件”理论似乎最适合。我使用下面的代码检查了规范的想法,无论是否存在 jtapi.jar,输出都是相同的:

File jtapiFile = new File(".", JTAPI_JARFILE);
try {
  LogMain("JtapiUpdater: getCanonicalPath() " +  jtapiFile.getCanonicalPath() + ".");
} catch (IOException e) {}

输出:
JtapiUpdater:getCanonicalPath() /home/ddg/aix/jtapi.jar。

但是,我仍然没有一个简单的方法来解决这个问题。

编辑:
我在 java 执行行中添加了跟踪选项:
-Dibm.cl.verbose=com.cisco.jtapi.extensions.CiscoProviderObserver
-Dibm.dg.trc.methods=java/lang/ClassLoader.*() -Dibm.dg.trc.print=mt

这些输出加载器如何找到类。这是它显示的内容......

如果 jtapi.jar 最初不存在但由 updater.jar 下载:

AppClassLoader attempting to find com.cisco.jtapi.extensions.CiscoProviderObserver
AppClassLoader using classpath /home/ddg/aix/ccm-tserver.jar:/home/ddg/aix/updater.jar:/home/ddg/aix/jtapi.jar
AppClassLoader could not find com/cisco/jtapi/extensions/CiscoProviderObserver.class in /home/ddg/aix/ccm-tserver.jar
AppClassLoader could not find com/cisco/jtapi/extensions/CiscoProviderObserver.class in /home/ddg/aix/updater.jar
AppClassLoader could not find com.cisco.jtapi.extensions.CiscoProviderObserver

如果 jtapi.jar 存在

AppClassLoader attempting to find com.cisco.jtapi.extensions.CiscoProviderObserver
AppClassLoader using classpath /home/ddg/aix/ccm-tserver.jar:/home/ddg/aix/updater.jar:/home/ddg/aix/jtapi.jar
AppClassLoader could not find com/cisco/jtapi/extensions/CiscoProviderObserver.class in     /home/ddg/aix/ccm-tserver.jar
AppClassLoader could not find com/cisco/jtapi/extensions/CiscoProviderObserver.class in /home/ddg/aix/updater.jar
AppClassLoader found com/cisco/jtapi/extensions/CiscoProviderObserver.class in /home/ddg/aix/jtapi.jar
AppClassLoader found com.cisco.jtapi.extensions.CiscoProviderObserver

请注意 AppClassLoader 在“不是”的情况下甚至不搜索 /home/ddg/aix/jtapi.jar,即使 jtapi.jar 已成功下载并列在类路径中!

我的猜测是,这是 AIX 7.1 的 JVM 中的一个错误,因为它在任何其他操作系统(包括早期版本的 AIX)上都不是问题。

【问题讨论】:

  • 您的问题不清楚。您是说第一次运行以NoClassDefFoundError 结束,后续运行成功?
  • 正确。在第一次运行期间,应用程序下载 jtapi.jar 然后失败并出现此异常。由于 jtapi.jar 已经存在,因此再次运行该应用程序。

标签: java jar aix noclassdeffounderror


【解决方案1】:

听起来 AIX 上的 JVM 可能有一个默认的类加载器,它在启动时检查类路径条目是否存在,并丢弃任何不存在的条目。但是,我无法在任何文档中验证这一点。

您不能等到所有 .jar 文件都下载完毕后再启动应用程序吗?

如果不能,您可能需要在代码中使用自定义类加载器,而不是调用 Class.forName()

编辑:我一直在挖掘:系统类加载器sun.misc.Launcher$AppClassLoader 将类路径条目转换为规范路径,然后创建一个文件数组他们的网址。但是a file that doesn't exist的规范路径是什么?

表示不存在的文件或目录的每个路径名也有唯一的规范形式。不存在的文件或目录的路径名的规范形式可能与创建文件或目录后相同路径名的规范形式不同。同样,现有文件或目录的路径名的规范形式可能与删除该文件或目录后相同路径名的规范形式不同。

也许在 AIX 上,现有文件和不存在文件的规范路径名不同?

【讨论】:

  • jtapi.jar 的下载由应用程序自己发起。它下载新文件的原因有 2 个:(1) 文件丢失或 (2) 版本不正确。这是设计使然。
  • 那么您应该使用新的类加载器并重构代码,以便在加载类之前下载 .jar。我什至见过人们下载类加载器并缓存 jar。
  • 谢谢。一个操作系统的一个版本只需要这样做,这似乎很奇怪。我们在许多操作系统的许多版本上都支持此应用程序,而不会出现此问题。我想知道 AIX 7.1 有什么特别之处...
  • 其实是在加载类之前先下载jar。成功下载jtapi.jar后出现上述异常。除非我错过了什么。
  • 那么似乎有某种机制可以从类路径中消除不存在的文件,或者使它们无法使用(见编辑)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-16
  • 2010-12-18
  • 2017-07-16
  • 2013-11-04
  • 1970-01-01
  • 2023-04-05
  • 2020-04-09
相关资源
最近更新 更多