さまざまなフェーズを持つ段階的なアプリケーションコンテキストを想像してみてください。必要なインフラストラクチャを定義するための初期段階から始めます。 xmlアプリケーションコンテキストは順番にロードされます。
これらのファイルを分割する理由は、拡張機能/プラグインメカニズムです。
ステージ01-default-configuration.xml
後でデータで拡張するために、ID exampleMapping
でマップを準備して宣言します。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="[...]">
<util:map id="exampleMapping" />
</beans>
ステージ02-custom-configuration.xml(オプション)
exampleMapping
を構成し、エントリを追加します。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="[...]">
<util:map id="exampleMapping">
<entry key="theKey" value="theValue" />
</util:map>
</beans>
ステージ03-make-use-of-configuration.xml(必須)
定義されたマップexampleMapping
を使用します。これは、カスタムで構成されているか、まだ空の宣言済みマップであるかは関係ありません。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="[...]">
<bean id="exampleService" class="com.stackoverflow.example.ExampleService">
<property name="mapping" ref="exampleMapping" />
</bean>
</beans>
ここでの問題は、最初の段階の後でexampleMapping
マップにエントリを追加できないことです。 Springは、IDがexampleMapping
のマップがすでに存在するという例外をスローします。最初のステージを省略すると、マップは宣言されておらず、3番目のステージはexampleMapping
を解決できず、これも例外を生成します。
この問題を解決するにはどうすればよいですか? Collection merging (spring docs)を読みましたが、これは役に立ちませんでした。後でマップ/リストに値を追加してから使用することはできますか?
ありがとうございました!
あなたcan define exampleMapping
は2番目の定義が別のファイルにあり、<import resource="..."/>
を使用して1つのファイルを別のファイルにインポートしますが、これは壊れやすいアプローチであり、簡単に壊れます。
より堅牢な戦略を提案します。 exampleMapping
をRegistry
クラスに置き換えます。このクラスには、マッピングが含まれ、管理されます。
public MappingRegistry<K,V> {
private final Map<K,V> mappings = new HashMap<K,V>();
public void addMapping(K key, V value) {
mappings.put(key, value);
}
public Map<K,V> getMappings() {
return Collections.unmodifiableMap(mappings);
}
}
次に、マッピングをレジストリに登録するクラスを記述します。
public class MappingRegistrar<K,V> {
private final MappingRegistry<K,V> registry;
private K key;
private V value;
@Autowired
public MappingRegistrar(MappingRegistry<K,V> registry) {
this.registry = registry;
}
public void setKey(K key) {
this.key = key;
}
public void setValue(V value) {
this.value = value;
}
@PostConstruct
public void registerMapping() {
registry.addMapping(key, value);
}
}
設定は次のようになります。
<bean id="mappingRegistry" class="com.xyz.MappingRegistry"/>
<bean id="mappingA" class="com.xyz.MappingRegistrar" p:key="keyA" p:value="valueA"/>
<bean id="mappingB" class="com.xyz.MappingRegistrar" p:key="keyB" p:value="valueB"/>
<bean id="mappingC" class="com.xyz.MappingRegistrar" p:key="keyC" p:value="valueC"/>
これらのマッピングは、適切と思われる方法で構成全体に分散させることができ、自己組織化されます。次に、ExampleServcie
にMappingRegistry
が挿入され、それに応じてマッピングが抽出されます。
これは、すでに持っているものよりも少し手間がかかりますが、はるかに柔軟性があり、エラーが発生しにくくなっています。これは、ある種の拡張可能なフレームワークを構築しようとしている場合に特に役立ちます。あなたは人々がそれをどのように使うかについてより少ない制約を課したいのです。
map
とlist
の両方に、2つのリストをマージするためのmerge=true|false
という名前のこの属性があります。または、MethodInvokingFactoryBean
を使用して、定義済みのリストのaddメソッドを呼び出し、後でアイテムを追加することもできます。
あなたの例を見てみましょう。
1)最初にMethodInvokingFactoryBean
を使用した2番目のシナリオ。あなたのやり方を定義する代わりに、私はあなたのBeanを少し異なって定義しました。
<bean class="Java.util.HashMap" id="exampleMapping">
<constructor-arg index="0">
<map>
<entry key="theKey" value="theValue"/>
</map>
</constructor-arg>
</bean>
<bean id="exampleService" class="com.stackoverflow.example.ExampleService">
<property name="mapping" ref="exampleMapping"/>
</bean>
別のアプリケーションコンテンツファイルで、次の操作を実行してマップを拡張できます。
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="exampleMapping"/>
<property name="targetMethod" value="putAll"/>
<property name="arguments">
<list>
<map id="exampleMapping">
<entry key="theKey2" value="theValue2"/>
<entry key="theKey3" value="theValue3"/>
<map>
</list>
</property>
</bean>
2)最初のシナリオです。これについては、ページで何かを見つけました http://forum.springsource.org/showthread.php?t=53358
<bean id="commonData" class="A">
<property name="map">
<util:map>
<entry key="1" value="1"/>
</util:map>
</property>
</bean>
<bean id="data" class="A" parent="commonData">
<property name="map">
<util:map merge="true">
<entry key="2" value="2"/>
</util:map>
</property>
</bean>
それが役に立てば幸い。