当前位置: 首页 > 知识库问答 >
问题:

自定义类加载器的问题与getResources的名称结束在斜杠

窦涵忍
2023-03-14

我非常需要帮助,但在网上找不到关于这个特定主题的任何东西(许多相关的问题没有得到回答)。

具体来说,我需要能够从中央和外部代码存储库下载代码(JAR)。这是由引导代码完成的,引导代码需要将其添加到类装入器的类路径中,以便以后使用。这就是我们进入这个已经讨论了很多次的话题的时候。我不喜欢黑客,所以我尝试了以下方法:

尝试#1:创建一个为此目的配置的URLClassLoader实例,然后通过它调用代码的“其余部分”。

失败:这里有1.5个问题(一个可能是另一个的原因)。一个是URLClassLoader通常更喜欢从其父级加载内容。有些代码必须存在于两个版本中,可能是不同的版本。如果使用来自父级的代码,它将继续使用“外部”类加载器进行剩余的加载,这不是我们想要的,即使初始加载是可以的。其次,一些第三方库似乎直接访问系统类加载器,无论是设计还是意外(可能从它加载的类之一获得)。

尝试#2:创建我的URLClassLoader子类,它更喜欢自己而不是父类。覆盖loadClass、getResources、getResources、getPackage、getPackages...以后的其他方法也可以确保这一点。

失败:没有帮助(足够)。第三方代码仍然无法加载某些资源。

尝试#3创建URLClassLoader的另一个自定义子类,并使用-Djava将其设置为系统类加载器。系统班加载器=。。。

失败:这效果更好——走得更远,但仍然未能获得资源。不过,这次是不同的资源。我向所有重写的方法添加了日志记录,以记录它们的调用和资源名称。经常资源大部分是找到的。有些人仍然没有,尽管他们在那里(得到证实)。但是我不知道的是,即使我努力学习,许多资源名称的调用都以斜杠结束。有些也有斜杠,通常会出现美元符号(嵌套/内部类资源)。一些被要求但未找到的例子:

com/acme/foo/bar/ClassName/com/acme/foo/bar/ClassName/InnerClassName/

当我运行下载的代码时,所有内容都在初始/引导类路径上(并且不使用我的类加载器),一切正常-因此我的类加载器破坏了一切,但我需要它工作。

我最接近的猜测是:

>

  • 第三方代码以某种方式获得了真正的系统类加载器,可能是通过它加载的某个类,然后使用它。我没有看到对它的请求,它们肯定会失败,因为它没有完整的类路径。

    资源名称以斜杠结尾的业务是由真正的系统类加载器支持的,而不是由我正在子类化的URLClassLoader支持的。我只能猜测理论收益URL以某种方式定位了以该名称为前缀的资源集合。这很难与之匹敌,尽管有可能。此外,一些斜杠似乎位于分隔内部类名的美元符号应该在的位置,即在上面的例子中(为清晰起见添加了空格):

    com/acme/foo/bar/ClassName/InnerClassName/

    com/acme/foo/bar/ClassName$InnerClassName/

    请注意,我不能通过假设实际系统类加载器是URLClassLoader的子类并使用反射调用其addURL(URL)方法来攻击它。

    有没有办法让这个工作?请帮帮忙!

    更新

    我只是做了一个额外的尝试。我创建了一个虚拟包装类加载器(扩展类加载器,而不是URLClassLoader),它只记录请求,然后将它们传递给父类(公共方法)或超类(受保护的方法)。我将其设置为系统类加载器,并手动将整个“内部”类路径添加到实际的外部路径,然后尝试运行代码。这是正确的,就像没有自定义系统类加载器一样。记录的内容还确定,即使是系统类加载器也会为这些资源返回null,其中大多数资源以斜杠结尾,但不是所有资源。我没有检查这些在我的真实代码中是否也有效,但猜测它们可能有效——因为它们不是绊脚石。不知何故,自定义系统类加载器仍然被绕过。怎样?

    更新2

    在我的自定义系统类加载器中,我让一些类来自外部/真正的系统类加载器,例如java.lang.中的类,我现在怀疑我不应该有,内部的“世界”必须完全隔离。然而,这将使与它通信成为问题,我只剩下反射了...但不确定这是否行得通——也就是说,java.lang.和/或java.lang.对象可以不止一个吗?

  • 共有2个答案

    单于海荣
    2023-03-14

    看起来,您不理解类加载器的结构。在当前版本的普通JVM中,至少有三个类装入器:

    1. 负责加载核心类的引导加载程序。因为这涉及类,比如ClassClassLoader本身,所以不能用ClassLoader实例来表示。其getClassLoader()返回null的所有类都是由引导加载程序加载的

    结论是,如果希望在不将委托给父加载程序破坏您的工作的情况下重新加载应用程序的类,则不需要操纵类加载程序的实现。您只需指定正确的父级。这很简单

    URLClassLoader cl=new URLClassLoader(urls, ClassLoader.getSystemClassLoader().getParent());
    

    这样,新类加载器的父类将是原始应用程序类加载器的父类,因此,已经加载的应用程序类不在新加载器的范围内,而其他一切都正常工作。

    关于以斜杠结尾的资源,它们是相当罕见的。它们可能在实际引用目录时得到解析,但这取决于URL的协议和该协议的实际处理程序。例如,它可能适用于file:URL,但通常不适用于jar:URL,除非jar文件包含目录的伪条目。我还看到它在ftp:url上工作。

    要理解的另一件事是,如果一个类直接引用另一个类,则将查询其原始定义类装入器,而不一定是应用程序类装入器。例如,当类java时。lang.String包含对java的引用。lang.Object(确实如此),此引用将使用引导加载程序直接解析,因为这是java的定义加载程序。lang.String

    这意味着,如果操纵加载程序的父级查找以不遵循标准的父级委派,则可能会将名称解析为不同的运行时类,就像解析由父级加载程序加载的类引用的相同名称一样。通过遵循上述解决方案中的标准步骤,可以避免此类问题。JRE类永远不会包含对应用程序类的引用,并且没有原始应用程序加载程序作为其父级的新加载程序永远不会干扰原始应用程序加载程序加载的类。

    翟沈义
    2023-03-14

    考虑到所有的限制因素,这似乎并不完全可能以我想要的坚如磐石的方式实现:

    a) 第三方库可能总是“行为不端”,并获得他们不应该以这种或那种方式使用的LassLoader。我按照fge的建议查看了OneJar,但它们有相同的问题——它们只检测到它的可能性。

    b) 无法完全替换/隐藏系统类装入器。

    c) 将系统类加载器强制转换为URLClassLoader可能随时停止工作。

     类似资料:
    • 本文向大家介绍java 类加载与自定义类加载器详解,包括了java 类加载与自定义类加载器详解的使用技巧和注意事项,需要的朋友参考一下 类加载 所有类加载器,都是ClassLoader的子类。 类加载器永远以.class运行的目录为准。 读取classpath根目录下的文件有以下几种方式: 1 在Java项目中可以通过以下方式获取classspath下的文件: 在Tomcat中tomcat又声明了

    • 我试图修改几个类的字节代码,这些类的打包jar文件不在类路径中-它们是在给定URL的运行时由自定义的加载的。我尝试使用和来拦截那些类,但失败了。类加载器是遗留项目的一部分,因此我无法直接对其进行更改。 代理可以很好地处理AppClassLoader“本地”加载的类,但只会忽略那些由自定义类加载器加载的类。 CustomClassLoader: 我的代理中使用的ClassFileTransforme

    • 我试图覆盖JAX-WS web服务的Apache CXF实现。根据JAX-WS=当安装Apache CXF时,它“窃取”默认的JDK JAX-WS实现,如何解决?,我正在尝试创建/覆盖提供程序实现。 有了这个配置,我们就有了javax。xml。ws。spi。至少在两个JAR中提供程序:/tomcat/lib/cxf rt frontend jaxws-*。jar和我们自己的jar/tomcat/w

    • 问题内容: 除了包级别注释外,还有其他方法可以使用注释来控制自定义名称空间前缀。 可以在元素级别完成吗?也可能有一个带有多个前缀的名称空间吗? 问题答案: 您实际上想做什么?为什么名称空间前缀对您很重要? 对于命名空间前缀,没有标准的元素级注释。 我知道的控制名称空间前缀的选项是: 你已经提到过。 提供习俗。 XML的低级处理(例如,在StAX,SAX或DOM级别)。 我也可以想象: / 通常使用

    • 我正在尝试创建一个定制的permalink结构,它将允许我完成以下任务。 我有一个自定义的帖子类型称为"项目" 我有一个自定义分类法,称为项目类别,分配给CPT项目 我希望我的永久链接结构如下所示: 项目/类别/项目-名称 或 /%自定义后类型%/%自定义分类%/%后名称%/ 创建这样的永久链接结构会如何影响URL或其他页面?是否可以取消定义自定义永久链接结构并将其限制为单个CPT? 谢谢

    • 问题内容: 我们有一个Angular应用程序,该应用程序获取一些输入参数,并将其发送到后端进行处理。处理结果是一个我们要在新选项卡中打开的pdf文件。 这样做的代码如下所示: 一切正常,但浏览器中的URL显示一些随机生成的字符串,如下所示: 显然,这对于最终用户来说看起来不太好,我们希望显示一些对用户有意义的内容,例如: 我是JS的新手,Angular的新手,HTML的新手,希望我的问题听起来不是