来自嵌套 jar 的 Java 9+ 类加载问题自定义 jarjar 协议

问题描述

我目前正在通过 Java 9 将应用程序从 Java 8 迁移到 Java 11。该应用程序使用自定义的可执行 war 框架,并利用此处的嵌套类解析代码http://pavel.savara.sweb.cz/files/JarJarURLConnection.java。此代码允许可执行 war 中的引导程序代码使用以下形式的 url 从其自己的存档中的 jar 加载类:

jar:jarjar:file:<path_to_war>^/WEB-INF/<path_to_jar>!/<path_to_class>

意图是初始 jar 协议使 JRE 将 jarjar:file:<path_to_war>^/WEB-INF/<path_to_jar> 视为要加载的资源,然后 !/ 之后的任何内容都是要加载的类的路径。

自定义 jarjar 协议处理程序解析请求的 url jarjar:file:<path_to_war>^/WEB-INF/<path_to_jar> 并将其替换为另一个 jar 协议 url:jar:file:<path_to_war>!/WEB-INF/<path_to_jar>(注意从 ^!).

这在 Java 8 之前都可以正常工作,但从 Java 9 开始就失败了,我不知道为什么。 JRE 似乎忽略了由 parseURL 创建的转换后的 url,并尝试使用没有来自 WEB-INF 的嵌套 jar 的普通战争位置。

非常感谢任何帮助。此代码是其他一些更复杂代码的一部分,因此我们希望不必重新编写整个代码

编辑: Github 存储库,包含基本代码和描述 Java 8 和 Java 11 之间行为差异的自述文件...

https://github.com/jugglingcats/execwar-test

编辑2: 在调试器中运行两者我可以看到路径完全不同,并且在 JDK11 上生成一个带有双 ! 的 url,它破坏了一切。

在 JDK8 中,当 parseUrl 被调用时,堆栈如下所示:

parseURL:111,JarJarURLConnection$JarJarURLStreamHandler (com.acme)
<init>:639,URL (java.net)
<init>:507,URL (java.net)
<init>:456,URL (java.net)
parseSpecs:175,JarURLConnection (java.net)
<init>:158,JarURLConnection (java.net)
<init>:81,JarURLConnection (sun.net.www.protocol.jar)
openConnection:41,Handler (sun.net.www.protocol.jar)
openConnection:1001,URL (java.net)
findResource:715,URLClasspath$Loader (sun.misc)
findResource:225,URLClasspath (sun.misc)
run:572,urlclassloader$2 (java.net)
run:570,urlclassloader$2 (java.net)
doPrivileged:-1,AccessController (java.security)
findResource:569,urlclassloader (java.net)
getResource:1089,ClassLoader (java.lang)
getResourceAsstream:233,urlclassloader (java.net)
main:23,Main (com.acme)

您可以看到我们已经在openConnection

在 JDK11 中它看起来像:

parseURL:111,JarJarURLConnection$JarJarURLStreamHandler (com.acme)
<init>:674,URL (java.net)
<init>:541,URL (java.net)
<init>:488,URL (java.net)
run:487,URLClasspath$3 (jdk.internal.loader)
run:476,URLClasspath$3 (jdk.internal.loader)
doPrivileged:-1,AccessController (java.security)
getLoader:475,URLClasspath (jdk.internal.loader)
getLoader:444,URLClasspath (jdk.internal.loader)
findResource:290,URLClasspath (jdk.internal.loader)
run:655,urlclassloader$2 (java.net)
run:653,AccessController (java.security)
findResource:652,urlclassloader (java.net)
getResource:1400,ClassLoader (java.lang)
getResourceAsstream:322,Main (com.acme)

问题似乎出在这两行(URLClasspath:487):

    URL nestedUrl = new URL(file.substring(0,file.length() - 2));
    return new JarLoader(nestedUrl,jarHandler,lmap,acc);

JarLoader 构造函数创建一个新的 jar url,如下所示:

        JarLoader(URL url,URLStreamHandler jarHandler,HashMap<String,Loader> loaderMap,AccessControlContext acc)
            throws IOException
        {
            super(new URL("jar","",-1,url + "!/",jarHandler));
            csu = url;
            handler = jarHandler;
            lmap = loaderMap;
            this.acc = acc;

            ensureopen();
        }

JarLoader.base 属性现在具有值 jar:jarjar:jar:file:webapp.war!/lib.jar!/,它会破坏事物。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)