假设我在classpath上有2个jar

JAR1:

Class1.class
resource.xml


JAR2:

Class2.class
resource.xml


类Class1和Class2使用类路径资源(每个JAR提供其自己的resource.xml并希望读取它)。

在我的应用程序中,我同时使用了jars,并且在加载Class1或Class2时,所加载的resource.xml是随机的(二者之一)。

Class1是否可以始终加载其resource.xml,而Class2自己加载?

最佳答案

我认为不可能完全按照自己的意愿去做。



让我们从有关类加载器和资源加载如何工作的一些事实开始


当您呼叫Class.getResource()时,它将变成对Class.getClassloader().getResource()的呼叫。
每个类只有一个类加载器。
每个类加载器只有一个父类加载器。
类加载器的构造方式可确保类加载器形成一棵严格的树,所谓的引导类加载器位于树的根。
类加载器可以使用以下两种策略之一来查找内容:


首先询问父类加载器,然后检查该类加载器的资源,
首先检查该类加载器的资源,然后询问父类加载器。



现在,为了论证,让我们考虑以下示例:

JAR1:

Class1.class
resource.xml
resource1.xml

JAR2:

Class2.class
resource.xml
resource2.xml


因此,让我们考虑一下如何将它们组合在一起:


如果JAR1和JAR2具有相同的类加载器,则该类加载器将无法知道首先应搜索哪个JAR。在类加载器上的getResource()调用不知道原始类是什么。
假设JAR1和JAR2具有不同的类加载器:


如果JAR2的类加载器是JAR1的父级,则它可以委托给JAR2,但是JAR2的类加载器不能委托给JAR1。如果我们调用Class2.class.getResource("resource1.xml"),则Class2的类加载器将无法委派给知道“ resource1.xml”的类加载器,并且加载将失败。
如果翻转它并使JAR1的类加载器成为JAR2的父级,那么我们会发现Class1.class.getResource("resource2.xml")将失败。

假设我们创建了两个都知道JAR1和JAR2的类加载器,并且两者都不委托给另一个。第一个类加载器可以在JAR1中查找资源,然后在JAR2中查找资源,然后在其父对象中查找,第二个类加载器可以在JAR2,JAR1父对象中查找资源。

到目前为止还可以。但是类加载呢?在这里,我们必须非常小心。我们不能允许两个类加载器都加载Class1.class的情况。因为如果发生这种情况,您最终会得到两个加载类型,它们具有相同的完全限定名称和不同的类加载器。但是Java类型系统说给我们提供了两种不同的类型……这很容易导致意外的ClassCastExceptions。因此,我们必须确保两个相应的类加载器不会同时加载同一类。

但这导致了另一个问题。如果要求第一个类加载器找到只有其他类加载器可以加载的类,则它不能委派给它...最终结果将是您将收到“找不到类”错误或异常。




总而言之,我认为我已经涵盖了所有可能的类加载器结构...并且它们都不适合我提出的示例。

可能会“违反规则”并建立有效的非树形结构的类加载器委托网络;例如通过使用后门告诉两个类加载器彼此有关。但是,存在最终以委托循环结束的风险……这将导致“无限”递归。即使这行之有效,也存在其他潜在风险;例如Java沙箱安全模型,它也依赖于类加载器的工作方式。

不要去那寻找另一种方法来做到这一点;例如为“ resource.xml”的两个版本使用不同的名称。

10-04 23:20