确保每个JAR首先看到自己的类路径资源

时间:2014-06-26 10:12:44

标签: java jar classpath

假设我在classpath上有2个罐子

JAR1:

Class1.class
resource.xml

JAR2:

Class2.class
resource.xml

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

在我的应用程序中,我使用两个jar,当加载Class1或Class2时,加载的resource.xml是随机的(两个中的一个)。

Class1是否可以始终加载其resource.xml和Class2?

1 个答案:

答案 0 :(得分:1)

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


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

  1. 当您致电Class.getResource()时,它会变成对Class.getClassloader().getResource()的通话。

  2. 每个班级只有一个类加载器。

  3. 每个类加载器只有一个父类加载器。

  4. 构造类加载器的方式确保类加载器形成一个严格的树,在树的根处有所谓的引导类加载器。

  5. 类加载器可以使用两种策略中的一种来查找内容:

    • 首先询问父类加载器,然后检查这个类加载器的资源
    • 首先检查这个类加载器的资源,然后询问父类加载器。
  6. 现在,为了论证,让我们考虑一下这个例子:

    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")会失败。

    • 假设我们创建了两个BOTH知道JAR1和JAR2的类加载器,并且没有委托给另一个。第一个类加载器可以在JAR1中查找资源,然后在JAR2中查找父级,第二个类加载器可以查找JAR2,JAR1,父级。

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

      但这会导致另一个问题。如果要求第一个类加载器找到只有另一个类加载器可以加载的类,那么它就不能委托给它......最终的结果就是你将得到一个“找不到类”的错误或异常。


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

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

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