【问题标题】:How to load one of same named resources from different jars in a classpath?如何从类路径中的不同 jar 加载相同命名的资源之一?
【发布时间】:2014-10-09 08:26:40
【问题描述】:

假设有一个 jar main.jar 依赖于另外两个 jar - dep1.jardep2.jar。这两个依赖项都位于main.jar 的 MANIFEST.MF 中的类路径中。每个依赖 jar 里面都有一个目录 foo,里面有一个文件 bar.txt

dep1.jar
|
\--foo/
   |
   \--bar.txt

dep2.jar
|
\--foo/
   |
   \--bar.txt

这里是main.jar的主类:

public class App
{
    public static void main( String[] args ) {
        ApplicationContext ctx = new StaticApplicationContext();
        Resource barResource = ctx.getResource("classpath:foo/bar.txt");
    }
}

将加载两个bar.txt 文件中的哪一个?有没有办法在资源 URL 中指定应该从其中加载文件的 jar?

【问题讨论】:

  • @Jenson 两个bar.txt不是一个类,所以不会有任何冲突。

标签: java spring jar embedded-resource


【解决方案1】:

翻转四分之一,这就是你会得到的。最有可能的是,它是按字母顺序排列的最高的,所以在您的情况下,它是 dep1.jar 中的那个。这两个文件都有相同的类路径(foo.Bar),虽然这应该看起来会引发编译时异常,但它不会因为它只会打包两个 jars 而不会尝试编译/查看(这个特定文件)文件因为它是一个 .txt 文件。

【讨论】:

    【解决方案2】:

    您不会期望编译时异常,因为资源加载是一个运行时过程。

    您无法在代码中指定资源来自哪个 jar,这是一个常见问题,尤其是当有人将 log4j.properties 之类的内容捆绑到 jar 文件中时。

    您可以做的是在您的类路径中指定 jar 的顺序,它会从列表中的第一个中获取资源。这本身就很棘手,因为当您使用 ivy 或 maven 之类的东西作为类路径依赖项时,您无法控制类路径中的顺序(无论如何在 eclipse 插件中)。

    唯一可靠的解决方案是将资源命名为不同的名称,或者将它们放在单独的包中。

    【讨论】:

      【解决方案3】:

      规范说类路径上的第一个类/资源被采用 (AFAIK)。

      不过我会尝试:

      Dep1Class.class.getResource("/foo/bar.txt");
      Dep2Class.class.getResource("/foo/bar.txt");
      

      由于 Class.getResource 工作不能从另一个 jar 中获取资源,而不是系统类加载器。

      如果运气好的话,您将不需要使用ClassLoaders 并使用不同的类加载器加载 dep2.jar。

      【讨论】:

      • 这不是真的,在具有绝对路径(斜线开头)的类上调用的 .getResource() 会查看类路径的根。将选择具有内部结构 /foo/bar.txt 的第一个 .jar。
      • @cobby 谢谢,这似乎是我很久以前就获得的误解。可能是因为getClass().getResource("foo.txt")很危险;可能是因为类加载器。
      【解决方案4】:

      你得到的是未定义的。但是,您可以使用

      Resource[] barResource = ctx.getResources("classpath*:foo/bar.txt");
      

      让他们都(全部)。 Resource 中的 URL 会告诉你它们在哪个 jar 中(尽管我不建议你根据这些信息开始编程)。

      【讨论】:

        【解决方案5】:

        正如@Sotirios所说,使用ctx.getResources(...)可以获取所有同名资源,代码如:

            ApplicationContext ctx = new StaticApplicationContext();
            Resource[] resources = ctx.getResources("classpath*:/foo/bar.txt");
        
            for (Resource resource : resources) {
        
                System.out.println("resource file: " + resource.getURL());
        
                InputStream is = new FileInputStream(resource.getFile());
        
                if (is == null) {
                    System.out.println("resource is null");
                    System.exit(-1);
                }
        
                Scanner scanner = new Scanner(is);
        
                while(scanner.hasNextLine()) {
                    System.out.println(scanner.nextLine());
                }
            }
        

        【讨论】:

          猜你喜欢
          • 2020-09-02
          • 1970-01-01
          • 1970-01-01
          • 2012-01-14
          • 1970-01-01
          • 2010-12-26
          • 1970-01-01
          • 1970-01-01
          • 2011-03-27
          相关资源
          最近更新 更多