【问题标题】:Java: Which of multiple resources on classpath JVM takes?Java:类路径 JVM 上的多个资源中的哪一个?
【发布时间】:2011-07-10 23:28:03
【问题描述】:

如果我在类路径上有多个同名文件(例如,我有多个 .jar 和 log4j.properties),JVM 遵循什么规则来选择一个?

【问题讨论】:

    标签: java resources jvm classpath loading


    【解决方案1】:

    它由使用-classpath选项指定资源(即通常是jar文件)的顺序指定。类路径上“较早”的资源优先于在它们之后指定的资源。这也可以在您的应用程序的清单文件中设置,然后您不需要提供-classpath 选项。您可能需要查看 these articles 以了解如何使用清单文件。

    “如何找到类”的详尽描述可以在here 找到,JAR-class-path Classes 部分描述了 JAR 文件搜索的逻辑。

    【讨论】:

    • 如果我使用 Maven,这是否意味着它实际上是随机的?测试时在 MANIFEST.MF 中设置类路径不起作用(jar 取自本地 repo)
    • 从 Maven 2.0.9 开始,这个可以处理,如here 所述。
    • 有任何官方文件可以确认Resources 'earlier' on the classpath take precedence over resources that are specified after them.?
    • 答案已更新,提供了描述类路径搜索逻辑的官方文档链接。
    • 除了已经说过的所有内容,您还可以使用ClassLoader.getResources(String name)。它返回具有给定名称的所有类路径资源,其顺序与答案中提供的链接中描述的顺序相同。如果您需要加载所有这些,这很有用。
    【解决方案2】:

    ClassLoader 确定资源的位置(取自 ClassLoader JavaDoc):

    ClassLoader 类使用委托模型来搜索类和资源。 ClassLoader 的每个实例都有一个关联的父类加载器。当请求查找类或资源时,ClassLoader 实例将在尝试查找类或资源本身之前将对该类或资源的搜索委托给其父类加载器。虚拟机的内置类加载器称为“引导类加载器”,它本身没有父级,但可以作为 ClassLoader 实例的父级。

    因此,无论在代码中调用 Class#getResource 或 Class#getResourceAsStream 的任何位置,都会发生这种情况(取自 Class.java)

    public java.net.URL getResource(String name) {
        name = resolveName(name);
        ClassLoader cl = getClassLoader0();
        if (cl==null) {
            // A system class.
            return ClassLoader.getSystemResource(name);
        }
        return cl.getResource(name);
    }
    

    类加载器.java:

    public URL getResource(String name) {
        URL url;
        if (parent != null) {
            url = parent.getResource(name);
        } else {
            url = getBootstrapResource(name);
        }
        if (url == null) {
            url = findResource(name);
        }
        return url;
    }
    

    其中 ClassLoader#findResource 实际上将被 ClassLoader 实现覆盖。这意味着在应用程序服务器、TomCat 上的行为是不同的,或者如果您从 jar 文件运行,这取决于您当前所在环境的 ClassLoader 实现。

    Here 是一个示例,您可以使用它来跟踪特定情况下的幕后情况。

    【讨论】:

    • 是的,它依赖于类加载器,但由于我使用的是标准类加载器的 Java SE,所以另一个答案适用。
    • 这应该添加使用通常的 URLClassLoader 时发生的情况,带有多个 jars/目录。
    【解决方案3】:

    我提供了一个经过验证的案例,如果类路径是文件夹中的所有 jar,并且您想要优先考虑其中一个(或一些),这是行不通的:

    窗户:

    bin/prioritized.jar;bin/*
    

    Linux:

    bin/prioritized.jar:bin/*
    

    似乎第一个路径 bin/prioritized.jar 被忽略了,因为第二个带有通配符的路径将它包含在自己的范围内。这有效地破坏了类路径的指定顺序。

    因此,为了优先处理多个资源(在 Java 10.0.1 上测试),您需要将它们放在不重叠的范围内,然后它们才能工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-12-26
      • 2010-10-26
      • 2010-12-08
      • 2011-12-15
      • 2013-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多