如何避免库罐中的资源冲突? [英] How to avoid resource collisions in library jars?
问题描述
我很担心当库 Foo
和 Bar
时,每个人都会暴露类路径上的资源相同的名称,在此示例中说 properties.txt
。
I'm worried about the situation when libraries Foo
and Bar
each expose a resource on the classpath with the same name, say properties.txt
in this example.
假设设置了Maven并且 jars
与Maven一起部署,如果我有这个设置:
Assuming a Maven set up and the jars
are deployed with Maven, if I have this set up:
Library Foo:
Library Foo:
$ cat Foo/src/main/resources/properties.txt
$ Foo
和图书馆栏:
$ cat Bar/src/main/resources/properties.txt
$ Bar
以及 App
取决于它们,其 pom
看起来像这样 - 简而言之,这只是说构建一个带依赖的jar,依赖于 Foo
和 Bar
:
And an App
that depends on them, whose pom
looks something like this - in a nutshell this just says "build a jar-with-dependencies, and depend on Foo
and 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
:
Problem is it really seems like the properties.txt
file was clobbered. Let's try a 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
所以我在 App
中运行了一个 main
类:
So I ran a main
class in App
that does:
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
哎呀,Bar赢了。 mvn package
-ing App
时没有警告或错误。运行时可能没有选择错误文件时出现警告或错误,实际上它无声地失败。
Whoops, Bar won. No warnings or errors when mvn package
-ing App
. No warnings or errors when running that the wrong file may have been chosen, in fact it failed silently.
所以我想要求正确的做法来避免这种情况。一,这样的事情应该大声失败,而不是轻轻地失败。第二,我能想到的唯一解决方案是所有资源文件都应该像Java开发中的其他所有资源一样正确打包,即库永远不会在code> properties.txt 中暴露全球命名空间;它应该出现在像 me / unroll / deptest / foo
这样的文件夹中,就像其他一切一样。我持怀疑态度,因为我没有看到任何实际上这样做的Maven示例。那么这里的最佳做法是什么?
So I want to ask proper practice to avoid this. One, something like this should fail loudly, not softly. Two, the only solution I can think is that all resource files should be properly packaged like everything else in Java development, i.e., a library should never expose properties.txt
in the "global" namespace; it should appear in a folder like me/unroll/deptest/foo
just like everything else. I'm skeptical because I haven't seen any Maven example that actually does this. So what is best practice here?
推荐答案
你在 Java 中做了什么来避免碰撞库?套餐!这是已建立并且易于理解的方法。包也适用于资源:
And what do you do in Java to avoid collisions between libraries? Packages! This is established and well understood approach. Packages work with resources as well:
com/example/foo/Foo.class
com/example/foo/properties.txt
和第二个库:
com/example/bar/Bar.class
com/example/bar/properties.txt
请注意, properties.txt
位于不同的包中,因此位于最终JAR中。实际上这种方法是首选,因为用于检索此类资源的API变得更容易:
Note that properties.txt
lies in different packages and thus directories in final JAR. Actually this approach is preferred because the API for retrieving such resources becomes easier:
App.class.getResourceAsStream("properties.txt"))
vs。
Bar.class.getResourceAsStream("properties.txt"))
It只是工作,因为 Class.getResourceAsStream()
默认是本地的基础类包。当然,当你在 Foo
或 Bar
的实例方法中时,你只需说 getClass ().getResourceAsStream( 的properties.txt)
。此外,您仍然可以轻松引用这两个文件,就像您引用类一样:
It just works because Class.getResourceAsStream()
is by default local to package of underlying class. Of course when you are inside an instance method of either Foo
or Bar
you simply say getClass().getResourceAsStream("properties.txt")
. Moreover you can still reference both files easily, just like you reference classes:
getClass().getResourceAsStream("/com/example/foo/properties.txt");
getClass().getResourceAsStream("/com/example/bar/properties.txt");
我是持怀疑态度,因为我没有看到任何实际上这样做的Maven示例。
I'm skeptical because I haven't seen any Maven example that actually does this.
真实世界的例子:你有一个名为的com集成测试com.example.foo.FooTest
。默认情况下,Spring期望上下文文件位于: /src/test/resources/com/example/foo/FooTest-context.xml
。
Real world example: you have a Spring integration test named com.example.foo.FooTest
. By default Spring expects the context file to reside under: /src/test/resources/com/example/foo/FooTest-context.xml
.
这篇关于如何避免库罐中的资源冲突?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!