在运行时加载jar会导致NoClassDefFoundError / ClassNotFoundException

时间:2014-10-02 01:05:13

标签: java jar dependencies runtime classloader

摘要: 从正在运行的Java程序加载jar会导致由NoClassDefFoundError引起的ClassNotFoundException由类间依赖性引起(例如import }语句)。我该如何解决这个问题?

更详细的问题:

我正在尝试以编程方式加载jar文件 - 让我们调用它" Server" - 通过我自己的Java程序进入Java虚拟机 - 让我们称之为" ServerAPI" - 并使用扩展和一些其他技巧来修改Server的行为并与之交互。 ServerAPI依赖于Server,但如果Server不存在,ServerAPI仍然必须能够从网站运行和下载Server。

为了避免因ServerAPI加载而导致的错误而不满足Server的依赖关系,我已经制作了一个启动器 - 让我们调用它" Launcher" - 用于下载服务器并根据需要设置ServerAPI,然后加载Server和ServerAPI,然后运行ServerAPI。

但是,当我尝试从Launcher加载jar时,我会收到错误,因为ClassLoader无法解析文件中其加载所依赖的类所依赖的其他类。简而言之,如果我尝试加载类A,如果A导入B,则会抛出错误,因为我还没有加载B。但是,如果B也导入A,我就会陷入困境,因为我无法弄清楚如何一次加载两个类,或者如何在没有JVM运行验证的情况下加载类

为什么所有限制都让我遇到了这个问题:

我正在尝试修改并添加到Server的行为,但由于复杂的法律原因,我无法直接修改程序,因此我创建了依赖的ServerAPI,并且可以从外部调整Server的行为。

但是,出于更复杂的法律原因,Server和ServerAPI不能简单地一起下载。 Launcher(见上文)必须与ServerAPI一起下载,然后Launcher需要下载Server。最后,可以使用Server作为依赖项运行ServerAPI。这就是为什么这个问题如此复杂的原因。

此问题也适用于项目的后续部分,该部分将涉及基于插件的API接口,该接口需要能够在运行时从jar文件加载和卸载插件。

我已就这个问题做过研究:

我已经阅读并且未能得到以下方面的帮助:

  • this question,它只解决单个方法的问题,不解决类间依赖性错误;
  • this question,这是行不通的,因为每次加载或卸载jar时我都无法关闭并重启程序(主要是我刚才提到的插件部分);
  • this question,仅适用于程序启动时存在依赖关系的情况;
  • this question,其问题与#2相同;
  • this question,其问题与#3相同;
  • this article,我从中了解了隐藏的loadClass(String,boolean)方法,但尝试使用 true false 值没有帮助; < / LI>
  • this question,其问题与#1相同;

等等。没有任何效果。

//编辑: 到目前为止我已尝试过:

我尝试使用URLClassLoaders使用JarEntries JarFile加载jar,类似于this question。我尝试使用并调用URLClassLoader的{​​{1}}方法并创建了一个扩展loadClass(String)的类,以便我可以利用URLClassLoader来尝试强制loadClass(String, boolean resolve)解析它加载的所有类。两种方式,我都有同样的错误:

ClassLoader

// END EDIT

//编辑2:

以下是我在尝试解析类时加载类的代码示例。这是我在一个扩展I couldn't find the class in the JarEntry! entry name="org/apache/logging/log4j/core/appender/db/jpa/converter/ContextMapAttributeConverter.class" class name="org.apache.logging.log4j.core.appender.db.jpa.converter.ContextMapAttributeConverter" java.lang.NoClassDefFoundError: javax/persistence/AttributeConverter at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:760) at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) at java.net.URLClassLoader.defineClass(URLClassLoader.java:455) at java.net.URLClassLoader.access$100(URLClassLoader.java:73) at java.net.URLClassLoader$1.run(URLClassLoader.java:367) at java.net.URLClassLoader$1.run(URLClassLoader.java:361) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:360) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at Corundum.launcher.CorundumClassLoader.load(CorundumClassLoader.java:52) at Corundum.launcher.CorundumLauncher.main(CorundumLauncher.java:47) Caused by: java.lang.ClassNotFoundException: javax.persistence.AttributeConverter at java.net.URLClassLoader$1.run(URLClassLoader.java:372) at java.net.URLClassLoader$1.run(URLClassLoader.java:361) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:360) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 12 more 的类中。在以URLClassLoader开头的行上,我尝试使用true和false作为布尔参数;两次尝试都导致了同样的错误。

Class<?> clazz = loadClass(

// END EDIT 2

我意识到必须有一个简单的解决方案,但对于我的生活,我似乎无法找到它。任何帮助都会让我永远感激不尽。谢谢。

1 个答案:

答案 0 :(得分:2)

令人尴尬的是,我发现答案是错误信息说实话。 javax.persistence.AttributeConverter,加载器声称的类不存在,不在jar中。

我通过只加载主类和ClassLoader所有引用类来解决这个问题,实质上是加载程序中使用的jar中的所有类,这就是我所需要的。

现在,我可以发誓我之前检查过这个并找到了这个课程;我想我在检查时必须实际检查过该类的Apache开源存储库而不是实际的服务器。我不记得了。

无论如何,AttributeConverter都缺失了。我不知道他们是如何或为什么设法编译一个缺少依赖项的jar,但我猜他们的主要进程从不使用代码的那部分,所以它永远不会抛出错误。

我很遗憾浪费每个人的时间......包括我自己的。我一直坚持这个问题一段时间了。

这个故事的道德:

如果您正在尝试加载可执行jar,请不要在jar中加载所有类,除非您确实需要。只需加载主类;这将加载程序运行所需的所有内容。

<强> //编辑:

我现在已经开始遇到相同的错误,但是在我尝试从加载的类调用方法之前它不会出现。问题显然仍然存在。请低估并忽略这个答案。