我很担心库Foo
和Bar
每个都在类路径上公开一个具有相同名称的资源时的情况,比如说这个例子中的properties.txt
。
假设设置了Maven并且使用Maven部署jars
,如果我已经设置了这个:
图书馆Foo:
$ cat Foo/src/main/resources/properties.txt
$ Foo
和图书馆栏:
$ cat Bar/src/main/resources/properties.txt
$ Bar
依赖于App
的{{1}},其pom
看起来像这样 - 简而言之,这只是说“构建一个依赖于jar的jar,依赖于Foo
和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
- App
时没有任何警告或错误。运行时可能没有选择错误文件的警告或错误,事实上它无声地失败。
所以我想要求正确的做法来避免这种情况。一,这样的事情应该大声失败,而不是轻声失败。第二,我能想到的唯一解决方案是所有资源文件都应该像Java开发中的其他所有资源一样正确打包,即库永远不会在“全局”命名空间中公开properties.txt
;它应该像其他所有内容一样出现在像me/unroll/deptest/foo
这样的文件夹中。我持怀疑态度,因为我没有看到任何实际上这样做的Maven示例。那么这里的最佳做法是什么?
答案 0 :(得分:3)
你在 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"))
VS
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集成测试。默认情况下,Spring期望上下文文件位于:/src/test/resources/com/example/foo/FooTest-context.xml
。
答案 1 :(得分:1)
要使用Maven代码完成@Tomasz的答案,请执行以下操作:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<targetPath>com/example/bar/</targetPath>
</resource>
</resources>
</build>