【问题标题】:URLClassLoader can't handle jar:file urls?URLClassLoader 无法处理 jar:file url?
【发布时间】:2016-06-04 19:56:59
【问题描述】:

我想在单独的类加载器中加载一个库,因为不想直接添加为依赖项,以免与项目中的其他版本冲突。 我创建了一个加载器:

public LibLoader(String resourcePath) {
    //resourcePath="/lib/Log4JHack-1.0.jar"
    URL url = getClass().getResource(resourcePath);
    loader = new URLClassLoader(new URL[] {url}, getClass().getClassLoader());
}

url = [file:/D:/..../lib/Log4JHack-1.0.jar]

如果 url 是一个文件,那么它运行良好

url = [jar:file:/C:/..../Log4JHackLoader-1.0.jar!/lib/Log4JHack-1.0.jar]

如果 url 是 jar:file(jar 中的 jar),那么它不起作用

ERROR StatusLogger Unable to open jar:jar:file:/C:/Users/Dani/.m2/repository/hu/daniel/hari/log4jhack/Log4JHackLoader/1.0/Log4JHackLoader-1.0.jar!/lib/Log4JHack-1.0.jar!/META-INF/log4j-provider.properties java.net.MalformedURLException: no !/ in spec
    at java.net.URL.<init>(URL.java:620)
    at java.net.URL.<init>(URL.java:483)
    at java.net.URL.<init>(URL.java:432)
    at java.net.JarURLConnection.parseSpecs(JarURLConnection.java:175)
    at java.net.JarURLConnection.<init>(JarURLConnection.java:158)
    at sun.net.www.protocol.jar.JarURLConnection.<init>(JarURLConnection.java:81)
    at sun.net.www.protocol.jar.Handler.openConnection(Handler.java:41)
    at java.net.URL.openConnection(URL.java:972)
    at java.net.URL.openStream(URL.java:1038)
    at org.apache.logging.log4j.util.ProviderUtil.loadProvider(ProviderUtil.java:79)
    at org.apache.logging.log4j.util.ProviderUtil.<init>(ProviderUtil.java:66)
    at org.apache.logging.log4j.util.ProviderUtil.lazyInit(ProviderUtil.java:122)
    at org.apache.logging.log4j.util.ProviderUtil.hasProviders(ProviderUtil.java:106)
    at org.apache.logging.log4j.LogManager.<clinit>(LogManager.java:91)
    at hu.daniel.hari.log4jpattern.logrenderer.log4j.log4j.capture.log4j2.StringLoggerCapture.<clinit>(StringLoggerCapture.java:34)
    at hu.daniel.hari.log4jpattern.logrenderer.log4j.Log4j2Hack.doRender(Log4j2Hack.java:30)
    at hu.daniel.hari.log4jpattern.logrenderer.log4j.Log4j2Hack.render(Log4j2Hack.java:23)
    at hu.daniel.hari.log4jpattern.logrenderer.log4j.renderer.AbstractLog4jRendererAdapter.render(AbstractLog4jRendererAdapter.java:25)
    at hu.daniel.hari.log4jpattern.logrenderer.service.LogRendererServiceImpl.getOutput(LogRendererServiceImpl.java:44)
    at hu.daniel.hari.log4jpattern.logrenderer.service.LogRendererServiceImpl.render(LogRendererServiceImpl.java:37)
    at hu.daniel.hari.log4jpattern.logrenderer.TestMain.main(TestMain.java:14)
Caused by: java.lang.NullPointerException: no !/ in spec
    at sun.net.www.protocol.jar.Handler.parseAbsoluteSpec(Handler.java:171)
    at sun.net.www.protocol.jar.Handler.parseURL(Handler.java:151)
    at java.net.URL.<init>(URL.java:615)
    ... 20 more

由于我想打包可加载的 Log4JHack-1.0.jar 到 Log4JHackLoader-1.0.jar,我需要一个从 jar 内部加载的解决方案

【问题讨论】:

    标签: java url classloader urlclassloader


    【解决方案1】:

    我不是 100% 清楚你在这里想要做什么。为什么要在类路径中包含冲突的依赖项?

    无论如何,这是UrlClassLoader 的已知限制。您是否考虑过将嵌套 jar 提取为文件系统上的临时文件,然后将您的类加载器指向它?

    【讨论】:

    • 这就是实际的资源路径。我正在为 log4j 创建一个测试器,所以我破解了 lib 来访问一些东西,我想把它与项目中 log4j 的正常使用区分开来。它正在工作,如果 jar 没有嵌套到另一个 jar,否则不会。
    • 看起来您正在使用 Maven。您是否考虑过使用 Shade 插件为您的更改创建一个补丁版本的 Log4J,这样您就不需要跳过类加载器箍? maven.apache.org/plugins/maven-shade-plugin
    • 是的,它使用 maven shade 插件制作了 Log4JHack-1.0.jar。资源路径与您的示例相同。但我想将整个故事打包在加载器模块中,以免硬编码的字符串类引用污染用户模块。因此,在正常加载加载器模块作为依赖项后,就会发生这种情况。
    • 有趣的是,你和我的步骤一模一样。 :) 是的,目前我将其作为临时文件写出来,但是我对这个解决方案不太满意。
    • 这是一个类加载器实现,它在内部尝试将嵌套的 jar 提取为临时文件。注意:我之前没有测试过这段代码,所以我不知道它的效果如何。 qdolan.blogspot.com/2008/10/…
    【解决方案2】:

    github.com/squark-io/nested-jar-classloader 项目能够加载嵌套 jar 文件中的类,但有很多外部依赖项。我在我的项目 (sourceforge.net/projects/mdiutilities/) 中添加了相同的机制,但在这种情况下没有外部依赖项。

    这两个项目不是通过制作嵌套jar文件的临时副本来工作,而是直接加载类字节。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-17
      • 2019-12-26
      • 1970-01-01
      • 2016-04-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多