9

我担心库FooBar每个库都在类路径上以相同名称公开资源的情况,例如properties.txt在这个例子中。

假设一个 Maven 设置并jars使用 Maven 部署,如果我有这个设置:

图书馆福:

$ cat Foo/src/main/resources/properties.txt
$ Foo

和图书馆酒吧:

$ cat Bar/src/main/resources/properties.txt
$ Bar

并且App依赖于它们,它pom看起来像这样 - 简而言之,这只是说“构建一个带有依赖关系的 jar,并依赖于Fooand Bar

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <executions>
    <execution>
      <id>bundle-project-sources</id>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
      <configuration>
        <archive>
          <manifest>
            <mainClass>me.unroll.deptest.App</mainClass>
            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
          </manifest>
          <manifestEntries>
            <Implementation-Build>${buildNumber}</Implementation-Build>
          </manifestEntries>
        </archive>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
    </execution>
  </executions>
</plugin>

问题是文件似乎真的properties.txt被破坏了。让我们尝试一下jar tf

unrollme-dev-dan:target Dan$ jar tf App-1.0-SNAPSHOT-jar-with-dependencies.jar 
META-INF/
META-INF/MANIFEST.MF
properties.txt
META-INF/maven/
META-INF/maven/me.unroll.deptest/
META-INF/maven/me.unroll.deptest/Bar/
META-INF/maven/me.unroll.deptest/Bar/pom.xml
META-INF/maven/me.unroll.deptest/Bar/pom.properties
META-INF/maven/me.unroll.deptest/Foo/
META-INF/maven/me.unroll.deptest/Foo/pom.xml
META-INF/maven/me.unroll.deptest/Foo/pom.properties
me/
me/unroll/
me/unroll/deptest/
me/unroll/deptest/App.class

所以我跑了一main堂课App

try (InputStream is = App.class.getClassLoader().getResourceAsStream("properties.txt")) {

    java.util.Scanner s = new java.util.Scanner(is);
        System.out.println("Scanner: " + s.next());

}

输出是:

unrollme-dev-dan:target Dan$ java -jar App-1.0-SNAPSHOT-jar-with-dependencies.jar 
Scanner: Bar

哎呀,巴尔赢了。mvn package-ing时没有警告或错误App。运行时没有警告或错误,可能选择了错误的文件,实际上它默默地失败了。

所以我想要求适当的练习来避免这种情况。一,这样的事情应该大声失败,而不是轻声细语。第二,我能想到的唯一解决方案是所有资源文件都应该像Java开发中的其他所有东西一样正确打包,即,一个库不应该暴露properties.txt在“全局”命名空间中;它应该me/unroll/deptest/foo像其他所有内容一样出现在一个文件夹中。我对此持怀疑态度,因为我还没有看到任何实际执行此操作的 Maven 示例。那么这里的最佳实践是什么?

4

2 回答 2

4

你在Java中做了什么来避免库之间的冲突?包裹!这是已确立且易于理解的方法。包也适用于资源:

com/example/foo/Foo.class
com/example/foo/properties.txt

第二个图书馆:

com/example/bar/Bar.class
com/example/bar/properties.txt

请注意,它properties.txt位于不同的包中,因此位于最终 JAR 中的目录中。实际上,这种方法是首选,因为用于检索此类资源的 API 变得更容易:

App.class.getResourceAsStream("properties.txt"))

对比

Bar.class.getResourceAsStream("properties.txt"))

它之所以有效,Class.getResourceAsStream()是因为默认情况下它是底层类包的本地。当然,当您在其中一个的实例方法中时,Foo或者Bar您只是说getClass().getResourceAsStream("properties.txt"). 此外,您仍然可以轻松引用这两个文件,就像引用类一样:

getClass().getResourceAsStream("/com/example/foo/properties.txt");
getClass().getResourceAsStream("/com/example/bar/properties.txt");

我对此持怀疑态度,因为我还没有看到任何实际执行此操作的 Maven 示例。

真实世界的例子:你有一个名为com.example.foo.FooTest. 默认情况下,Spring 期望上下文文件位于:/src/test/resources/com/example/foo/FooTest-context.xml.

于 2013-02-18T17:56:09.087 回答
2

要使用 maven 代码完成 @Tomasz 的回答:

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <targetPath>com/example/bar/</targetPath>
        </resource>
    </resources>
</build>
于 2019-02-07T08:24:00.973 回答