9

Fooこの例のように、ライブラリとBarそれぞれが同じ名前のクラスパス上のリソースを公開する状況が心配ですproperties.txt

Mavenがセットアップされ、Mavenjarsとともにデプロイされていると仮定すると、これをセットアップしている場合は次のようになります。

Library Foo:

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

およびライブラリバー:

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

そして、Appそれは彼らに依存し、そのpomように見えます-一言で言えば、これは単に「依存関係のある瓶を構築し、依存し、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-ing時に警告やエラーは発生しませんApp。実行時に間違ったファイルが選択された可能性があるという警告やエラーはありません。実際、サイレントに失敗しました。

ですから、これを避けるために適切な練習をお願いしたいと思います。1つは、このようなものは、静かにではなく、大声で失敗するはずです。2つ目は、私が考えることができる唯一の解決策は、すべてのリソースファイルをJava開発の他のすべてと同じように適切にパッケージ化する必要があることです。つまり、ライブラリはproperties.txt「グローバル」名前空間で公開しないでください。me/unroll/deptest/foo他のすべてと同じようにフォルダに表示されるはずです。実際にこれを行うMavenの例を見たことがないので、私は懐疑的です。では、ここでのベストプラクティスは何ですか?

4

2 に答える 2

4

そして、ライブラリ間の衝突を避けるためにJavaで何をしますか?パッケージ!これは確立され、よく理解されているアプローチです。パッケージはリソースでも機能します。

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

および2番目のライブラリ:

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の例を見たことがないので、私は懐疑的です。

実際の例:という名前のSpring統合テストがありcom.example.foo.FooTestます。デフォルトでは、Springはコンテキストファイルが次の場所にあることを想定しています/src/test/resources/com/example/foo/FooTest-context.xml

于 2013-02-18T17:56:09.087 に答える
2

@Tomaszの回答をMavenコードで完成させるには:

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