2008-09-16 15 views
2

のは、我々は次のJavaコードを持っていると仮定しましょう:列挙型のマップと依存性注入

public class Maintainer { 
    private Map<Enum, List<Listener>> map; 

    public Maintainer() { 
     this.map = new java.util.ConcurrentHashMap<Enum, List<Listener>>(); 
    } 

    public void addListener(Listener listener, Enum eventType) { 
     List<Listener> listeners; 
     if((listeners = map.get(eventType)) == null) { 
     listeners = new java.util.concurrent.CopyOnWriteArrayList<Listener>(); 
     map.put(eventType, listeners); 
     } 
     listeners.add(listener); 
    } 
} 

このコードスニペットは、各リスナーがイベントの種類を言っているビット改善リスナーパターン以外の何ものでもありません関心があり、提供されたメソッドはこれらの関係の同時マップを維持します。

は当初、私はこの方法は、私自身のアノテーションフレームワークを経由して呼び出すことがしたかったが、様々な注釈の制限のレンガの壁にぶつかった(例えば、あなたが注釈のparamとしてjava.lang.Enumを持つことができない、もありますさまざまなクラスローダー問題のセット)は、Springを使用することに決めました。

誰も私にどのように私にSpring_ify_を教えてもらえますか?私が達成したいのは、
です。メンテナクラスをSpring beanとして定義します。
2.すべてのリスナーが、addListenerメソッドを使用して、メンテナにXMLで登録できるようにします。春のdocやGoogleは非常に寛大な例です。

これを簡単に達成する方法はありますか? addListenerと「メンテナ」インタフェース(リスナー、列挙型)メソッドを定義

次のようなことをやってと間違っているだろう何

答えて

2

メンテナを実装するDefaultMaintainerクラス(上記)を作成します。

次に、各Listenerクラスで、Maintainerインターフェイスを「挿入」します(コンストラクタインジェクションは良い選択かもしれません)。リスナーは、Maintainerに自身を登録できます。

それ以外の場合、現時点であなたの難しさが正確にはわかりません。 :)

0

あなたは 注釈のparam "あなたがとしてjava.lang.Enumを持つことができません..." と...」

私はあなたがそれで間違っていると思う。私は最近持っていますこのようなプロジェクトの何かに使用:

public @interface MyAnnotation { 
    MyEnum value(); 
} 
+0

まあ、それは私が言ったまさにだ - "あなたは注釈PARAMとしてjava.lang.Enumを持つことができません"。私は春にこれをどうやってやるのですか? – mindas

1

1)のSpring Beanとしてメンテナクラスを定義

標準春の構文が適用されます。

<bean id="maintainer" class="com.example.Maintainer"/> 

2)のリスナーのすべての種類は、addListenerメソッドを使用してXMLを介しメンテナために自分自身を登録することが可能であろうように、それを確認します。春のdocやGoogleは非常に寛大な例です。

これは扱いにくいです。あなたは個別にそうように、maintainer#addListenerを呼び出すためにMethodInvokingFactoryBeanを使用することができます。

<bean id="listener" class="com.example.Listener"/> 

<bean id="maintainer.addListener" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> 
    <property name="targetObject" ref="maintainer"/> 
    <property name="targetMethod" value="addListener"/> 
    <property name="arguments"> 
    <list> 
     <ref>listener</ref> 
     <value>com.example.MyEnum</value> 
    </list> 
</property> 
</bean> 

しかし、これは扱いにくいです、そして潜在的にエラーが発生しやすいです。私はプロジェクトで何か似たような試みを行い、Springのユーティリティクラスを作成しました。私は現時点でソースコードを入手できませんので、私が行ったことを実装する方法を説明します。

1)リファクタリングのイベントタイプは、コンテキストに関連するすべてのリスナーを見つけスプリングヘルパークラスを作成)

public void addListener(MyListener listener) 

2に登録方法を変更MyListenerインタフェース

public interface MyListener extends Listener { 
    public Enum[] getEventTypes() 
} 

に耳を傾け見つかった各リスナに対して、maintainer#addListenerを呼び出します。私はBeanFilteringSupportで始まり、すべてのBeanがインスタンス化された後に豆を登録するためにBeanPostProcessor(またはApplicationListener)を実装します。

0

ありがとうございました。まず、すべての回答をすばやくフォローアップします。
1.具体的にはenumを注釈パラメータとして使用できますが、java.lang.Enumでは使用できません。
2.フリッケが提供する回答は正しいが、残念ながら少し怖い。私はSpringのエキスパートではありませんが、簡単なSpringアクセスのためのメソッドを作成するこのようなやり方をしています。MethodInvokingFactoryBeanソリューションのように、ちょっと残酷すぎるようです。私はあなたの時間と労力のために心から感謝しています。
3. Phillの答えは、(リスナーBeanを注入するのではなく、そのメンテナを注入するのではなく)ちょっと変わったですが、利用可能なものの中で最もクリーンです。私はこの道を行くと思う。

もう一度、お世話になりました。

2

少しofftopic(これは春ではないので)が、競合状態がのaddListenerの実装であり:

if((listeners = map.get(eventType)) == null) { 
    listeners = new java.util.concurrent.CopyOnWriteArrayList<Listener>(); 
    map.put(eventType, listeners); 
    } 
    listeners.add(listener); 

2つのスレッドが以前にイベントタイプのために(同時に、このメソッドを呼び出した場合リスナーを持たない)、map.get(eventType)は両方のスレッドでnullを返し、各スレッドは独自のCopyOnWriteArrayList(それぞれ単一のリスナーを含む)を作成し、一方のスレッドは他方のスレッドによって作成されたリストを置き換え、忘れられたこの問題を解決するには

、変更:

private Map<Enum, List<Listener>> map; 

... 

map.put(eventType, listeners); 

へ:

private ConcurrentMap<Enum, List<Listener>> map; 

... 

map.putIfAbsent(eventType, listeners); 
listeners = map.get(eventType); 
+0

ニースキャッチ、ありがとう! – mindas