假设我在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?
答案 0 :(得分:1)
我认为不可能完全按照自己的意愿行事。
让我们从关于类加载器和资源加载如何工作的一些事实开始
当您致电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")
会失败。
假设我们创建了两个BOTH知道JAR1和JAR2的类加载器,并且没有委托给另一个。第一个类加载器可以在JAR1中查找资源,然后在JAR2中查找父级,第二个类加载器可以查找JAR2,JAR1,父级。
好到目前为止。但是类加载怎么样?在这里,我们必须非常小心。我们不能允许两个类加载器都可以加载Class1.class的情况。因为如果发生这种情况,最终会得到两个具有相同完全限定名称和不同类加载器的加载类型。但是Java类型系统说它给了我们两个不同的类型......这很容易导致意外的ClassCastExceptions
。因此,我们必须确保两个相应的类加载器不都加载相同的类。
但这会导致另一个问题。如果要求第一个类加载器找到只有另一个类加载器可以加载的类,那么它就不能委托给它......最终的结果就是你将得到一个“找不到类”的错误或异常。
总之,我认为我已经涵盖了所有合理的类加载器结构......并且它们都不适用于我提出的示例。
有可能“违反规则”并设置有效非树结构类加载器委派网络;例如通过使用后门告诉两个类加载器彼此。但是,您最终会遇到委托循环......这将导致“无限”递归。即使这是有效的,也存在其他潜在的风险;例如Java沙箱安全模型,它依赖于类加载器的工作方式。
不要去那里。找到另一种方法来做到这一点;例如对“resource.xml”的两个版本使用不同的名称。