私が達成したいのは、子Spring XMLコンテキストのインポートを「動的に」(つまり、構成ファイルで定義されたプロパティに基づいて)有効/無効にする機能です。
私は次のようなものを想像します:
<import condition="some.property.name" resource="some-context.xml"/>
プロパティが(ブール値に)解決される場所で、trueの場合はコンテキストがインポートされます。それ以外の場合はそうではありません。
これまでの私の研究の一部:
カスタムNamespaceHandler(および関連クラス)を作成して、独自の名前空間に独自のカスタム要素を登録できるようにします。例えば: <myns:import condition="some.property.name" resource="some-context.xml"/>
このアプローチの問題は、Springからのリソースインポートロジック全体を複製したくないため、これを行うために委任する必要があるものが明確でないことです。
DefaultBeanDefinitionDocumentReader
をオーバーライドして、「import」要素の解析と解釈の動作を拡張します(importBeanDefinitionResource
メソッドで発生します)。ただし、この拡張機能をどこで登録できるかわかりません。これは、Spring 4を使用して完全に可能になりました。
メインアプリケーションコンテンツファイル内
<bean class="com.example.MyConditionalConfiguration"/>
MyConditionalConfigurationは次のようになります
@Configuration
@Conditional(MyConditionalConfiguration.Condition.class)
@ImportResource("/com/example/context-fragment.xml")
public class MyConditionalConfiguration {
static class Condition implements ConfigurationCondition {
@Override
public ConfigurationPhase getConfigurationPhase() {
return ConfigurationPhase.PARSE_CONFIGURATION;
}
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// only load context-fragment.xml if the system property is defined
return System.getProperty("com.example.context-fragment") != null;
}
}
}
そして最後に、必要なBean定義を/com/example/context-fragment.xmlに含めます
@ ConditionalのJavaDoc を参照してください
Spring 4より前のバージョンでは、標準のSpringコンポーネントを使用して最も近いものを入手できます。
<import resource="Whatever-${yyzzy}.xml"/>
ここで、${xyzzy}
は、システムプロパティからプロパティを補間します。 (ロードプロセスを開始する前に、システムプロパティオブジェクトに他の場所からプロパティを追加するコンテキストローダークラスのハックカスタムバージョンを使用します。)
しかし、不必要なものを大量にインポートすることもできます。また、さまざまなトリックを使用して、必要なBeanのみをインスタンス化します。これらのトリックは次のとおりです。
Spring 3.1.xでは、 bean profiles を使用して、条件付きリソースのインポートとBeanのインスタンス化を実現できます。以前のバージョンを使用している場合、これはもちろん役に立ちません:)
前述したように、Spring 3.1以降を使用している場合、これはプロファイルを使用して簡単に実現できます。
<!-- default configuration - will be loaded if no profile is specified -->
<!-- This will only work if it's put at the end of the configuration file -->
<!-- so no bean definitions after that -->
<beans profile="default">
<import resource="classpath:default.xml" />
</beans>
<!-- some other profile -->
<beans profile="otherProfile">
<import resource="classpath:other-profile.xml" />
</beans>
otherProfileは、たとえば.
mvn install -Dspring.profiles.active=otherProfile
テストで異なるプロファイルを使用している場合は、-DforkMode=never
テストが同じVM内で実行されるようにするため、param spring.profiles.active
失われない
記録のために、Robert Maldonは、この投稿でBeanの条件付き定義を達成する方法について説明しています。 http://robertmaldon.blogspot.com/2007/04/conditionally-defining-spring-beans.html 。ここでコピーするのには少し時間がかかります(とにかく、彼の記事をコピーアンドペーストする必要はないと思います)。
あなたの例に合わせたこのアプローチの最終結果は次のとおりです。
<condbean:cond test="${some.property.name}">
<import resource="some-context.xml"/>
</condbean:cond>
確かに、Stephen Cのソリューションほど単純ではありませんが、はるかに強力です。
独自のContextLoaderListenerでcontextInitialized(javax.servlet.ServletContextEventイベント)をオーバーライドし、このように呼び出されるsuper.contextInitialized(event)の前に必要なシステムプロパティを設定できます。
package com.mypackage;
import org.springframework.web.context.ContextLoaderListener;
public class MyContextLoaderListener extends ContextLoaderListener {
public void contextInitialized(javax.servlet.ServletContextEvent event) {
System.setProperty("xyz", "import-file-name.xml");
super.contextInitialized(event);
}
}
そして、web.xmlでContextLoaderListenerをMyContextLoaderListenerに置き換えます
<listener>
<listener-class>com.mypackage.MyContextLoaderListener</listener-class>
</listener>
これで、spring.xmlで使用できます
<import resource="${xyz}" />
これが役立つことを願っています。
Spring 3.0で考慮すべきもう1つ:
<alias name="Whatever" alias=""Whatever-${yyzzy}" />
ここで、${xyzzy}
は、システムプロパティからプロパティを補間します。
もう1つのオプションは、/ confフォルダーにあるmodules-config.xmlファイルをアプリにロードし、インストール/構成段階で編集して、ロードするモジュールのコメントを外すことです。
これは、さまざまな統合モジュールのコンテナとして機能するWebアプリケーションで使用しているソリューションです。 Webアプリケーションは、すべての異なる統合モジュールとともに配布されます。 modules-config.xmlはTomcatの/ confフォルダーに配置され、confフォルダーがクラスパスに追加されます(catalina.properties/common.loaderプロパティーを使用)。私のWebアプリwebapp-config.xmlには<import resource="classpath:/modules-config.xml"/>
ロードします。