2

私の java-spring-maven Web アプリケーションでは、複数のスプリング コンテキスト (プロジェクトごとに 1 つのコンテキスト) を使用しています。簡単にするために、2 つのスプリング コンテキスト a.xml と b.xml があり、それぞれがプロジェクト A とプロジェクト B に属し、A が B に依存しているとします。

a.xml は、次のように b.xml をインポートしています。

<import resource="classpath*:/b.xml" />

したがって、a.xml をロードすると、b.xml もロードされます。

現在、私のシステムには 2 つのスプリング プロファイルがあります。コンテキストで使用される te​​stとproductionです (プロファイルごとに異なるプロパティ プレース ホルダーをロードします)。

だから私は得たa.xmlで:

<!-- Production profile -->
<beans profile="production">
    <context:property-placeholder
        location="classpath:props-for-a.properties"
        ignore-unresolvable="true" ignore-resource-not-found="true" />
</beans>

<!-- Test profile -->
<beans profile="test">
    <context:property-placeholder
        location="classpath*:test-props-for-a.properties"
        ignore-unresolvable="true" />
</beans>

そして、b.xml での同じ規則 (異なるプロパティ ファイルのみをロードする)。プロパティ ファイルは src/main/resources (運用ファイル) と src/test/resources (テスト ファイル) の下にあります。

これで、次のような単体テストができました。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:/a.xml" })
@ActiveProfiles(profiles = "test")
public class SomeTestClass {

    @Test
    public void testMethod() {
    //Some Test
    }
}

この場合、a.xml は「テスト」プロファイルにロードされ、期待どおりに目的のファイルがロードされます (test-props-for-a)。b.xml は a.xml によってインポートされますが、b.xml からロードされたプロパティ ファイルのプロパティ値が挿入されないという奇妙な経験が発生しました。

たとえば、プロパティ ファイルに次のプロパティがあるとします。

connection-ip=1.2.3.4

そして私のクラスで私は得ました:

@Value("${connection-ip}")
private String connectionIP;

connectionIP の値は、「1.2.3.4」ではなく「${connection-ip}」になります。

ファイルの場所が で始まりclasspath*、* が含まれていないことに注意してください。FileNotFoundException が発生します。

Caused by: org.springframework.beans.factory.BeanInitializationException: Could not load properties; nested exception is java.io.FileNotFoundException: class path resource [test-props-for-b.properties] cannot be opened because it does not exist 

明確にするために、ファイル test-props-for-b.properties はプロジェクト B の src/test/resources の下にあります。なぜこれを取得するのですか?

b.xml を直接 (a.xml 経由でインポートせずに) ロードするテストを実行すると、正常に動作し、ファイル test-props-for-b.properties のテスト プロパティが期待どおりにロードされます。

私は何か間違ったことをしていますか?これはバグでしょうか?もしそうなら、回避策を提案できますか?

アップデート

プロパティ ファイル (test-props-for-b.properties) へのパスからスター (*) を削除し、Spring コードをデバッグしました。クラス ClassPathResource では、このメソッドは例外をスローします。

public InputStream getInputStream() throws IOException {
    InputStream is;
    if (this.clazz != null) {
        is = this.clazz.getResourceAsStream(this.path);
    }
    else {
        is = this.classLoader.getResourceAsStream(this.path);
    }
    if (is == null) {
        throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
    }
    return is;
}

変数の値は次のとおりです。

this.clazz はヌルです。this.path はファイル名 test-props-for-b.properties を保持します

そして、このコマンドは null を返します。

this.classLoader.getResourceAsStream(this.path);

何故ですか?プロジェクト B の src/test/resources の下にファイルがはっきりと表示されます。

4

2 に答える 2

1

この問題を調査した結果、これが私の結論です。

適切なクラスローダを使用できれば、ファイルは簡単にロードできます。つまり、プロジェクト A からファイルをロードするために、プロジェクト A のクラスの任意のクラスローダが、プロジェクト B と同じようにトリックを実行できます。 Spring のプロパティ プレースホルダーを使用すると ClassPathResource.java のクラス ローダーが使用され、別のプロジェクトからリソースをロードしようとすると失敗します (ClassPathResource はプロパティ プレースホルダーごとに初期化されるため、私のプロジェクトごとに場合)。

修正方法がよくわかりません。現在、テストプロパティファイルを複製することで醜い回避策を実装しています(プロジェクトAのsrc/test/resourcesフォルダーにファイルtest-props-for-b.propertiesを追加しました。この方法でプロジェクト B と A の src/test/resource にも複製します)。

私はまだきれいな方法を探しています。

于 2013-10-27T07:21:55.367 に答える