2011-01-11 11 views
15

相が異なる段階的なアプリケーションコンテキストを想像してみてください。必要なインフラストラクチャを定義するための初期段階から始めます。 xmlアプリケーションコンテキストは順番に読み込まれます。Springアプリケーションコンテキストですでに定義されているリストとマップを拡張する方法は?

これらのファイルを分割する理由は、拡張機能/プラグインのメカニズムです。

ステージ01-デフォルト-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-カスタム-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-メーク利用-の-configuration.xmlの(必須)

それはcustomly構成されたか、それはまだ空の宣言マップですだかどうか、定義されたマップ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(春のドキュメント)を読むが、これは役に立たなかった。後で値をマップ/リストに追加することは可能ですか?

ありがとうございました!

+0

「最初のステージの後にエントリで拡張することはできません」とはどういう意味ですか? – skaffman

+0

@skaffman:申し訳ありませんが、ftfy。 – codevour

答えて

10

は、2番目の定義は別のファイルにある、とあなたは別のものに1つのファイルをインポートする<import resource="..."/>を使用しますが、それは壊れやすいアプローチだと、簡単に壊れています。

私はより堅牢な戦略を提案します。

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); 
    } 
} 

あなたの設定のようなものになり:レジストリでマッピングを登録するクラスを記述し、その後

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); 
    } 
} 

:順番に含まれているとのマッピングを管理Registryクラス、とexampleMappingを交換してくださいこれは:

<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"/> 

これらのマッピングは、あなたの状況に合わせて任意の設定で散在させることができ、自己集合します。次にExampleServcieMappingRegistryが注入され、それに応じてマッピングが抽出されます。

これは既に持っているものよりもう少し仕事ですが、より柔軟でエラーの発生が少ないです。これは、ある種の拡張可能なフレームワークを構築しようとしている場合に特に有用です。人々がそれをどのように使用するかについての制約を少なくする必要があります。

+0

私は既にこのメカニズムを使用して、特別な種類のフィルタ/バリュープロバイダーに拡張可能な機能を提供しました。これは多くのオーバーヘッドになるだろうと思って、リスト/マップでこれを達成する簡単な方法があります。どうやらない。あなたが提案したように私はそれを実装します。多分私たちはそのような春の特徴を将来見るでしょうか?ありがとうございました! – codevour

+0

@codevour:これは残酷だとは思わないが、これは良いデザインだと思う。私の意見では、裸のマップを使用するよりも、より堅牢で、明示的で、読みやすいです。 – skaffman

+1

これは非常に一般的な方法ですが、豆は匿名にすることもできます。それについて少し考えましたが、これは私のアプローチに適しています。ありがとうございました。 – codevour

13

maplistの両方には、2つのリストをマージするためのmerge=true|falseという名前のこの属性があります。あるいは、既に定義済みのリストのaddメソッドを呼び出して後で余分な項目を追加する場合はMethodInvokingFactoryBeanを使用できます。

あなたの例を見てみましょう。

1)MethodInvokingFactoryBeanと第一、第二のシナリオ。あなたのやり方を定義する代わりに、私はあなたの豆を少し違って定義しました。別のアプリケーション・コンテンツ・ファイルで

<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)今すぐ最初のシナリオ。この1のために、私はちょうどページ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> 

に何かを見つけ、それがお役に立てば幸いです。あなたexampleMappingを定義することができ

+0

簡単な例がありますか?残念ながら、私はそれを実行することはありません。 – codevour

+0

私は答えを更新し、両方のオプションの例を挙げました。 –

+0

私は最初のシナリオはこのアプローチのための素晴らしいデザインではないと思うし、私には非常に汚いと思う。 2番目は少しわかりにくいですが、私はskaffmannがレジストリを書くのは最高だと思っています。あなたの答えと説明をありがとう! – codevour

関連する問題