3

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

このコード スニペットは、各リスナーが関心のあるイベントの種類を伝え、提供されたメソッドがこれらの関係の同時マップを維持する、少し改善されたリスナー パターンに他なりません。

当初、私はこのメソッドを独自の注釈フレームワーク経由で呼び出すことを望んでいましたが、さまざまな注釈制限のレンガの壁にぶつかりました (たとえば、java.lang.Enumを注釈パラメーターとして使用することはできません。さまざまなクラスローダーの問題もあります)。したがって、Spring を使用することにしました。

これを Spring_ify_ する方法を誰か教えてもらえますか? 私が達成したいことは次のとおりです。 1. Maintainerクラスを Spring Bean として
定義します。2. addListenerメソッドを使用 して、あらゆる種類のリスナーがXML 経由で自身をMaintainerに登録できるようにします。Spring docもGoogleも例に非常に寛大です。

これを簡単に達成する方法はありますか?

4

5 に答える 5

3

次のようなことをすると何が問題になりますか。

addListener(Listener、Enum)メソッドを使用して「Maintainer」インターフェースを定義します。

Maintainerを実装するDefaultMaintainerクラスを(上記のように)作成します。

次に、各Listenerクラスで、Maintainerインターフェースを「注入」します(コンストラクター注入が適切な選択である可能性があります)。その後、リスナーは自分自身をMaintainerに登録できます。

それ以外は、現時点でのSpringの難しさを100%明確に把握しているわけではありません。:)

于 2008-09-16T11:51:23.773 に答える
2

少し話題から外れていますが (これは Spring に関するものではないため)、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 (それぞれが 1 つのリスナーを含む) を作成します。 1 つのスレッドが別のスレッドによって作成されたリストを置き換え、最初のリスナーは忘れられます。

これを修正するには、次のように変更します。

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

...

map.put( eventType, listeners );

に:

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

...

map.putIfAbsent( eventType, listeners );
listeners = map.get( eventType );
于 2008-09-18T15:13:51.167 に答える
1

1) Maintainer クラスを Spring Bean として定義します。

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

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

2) addListener メソッドを使用して、あらゆる種類のリスナーが XML 経由で自身を Maintainer に登録できるようにします。Spring docもGoogleも例に非常に寛大です。

これはよりトリッキーです。次のように、を個別に呼び出すために使用できます。MethodInvokingFactoryBeanmaintainer#addListener

<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ユーティリティクラスを作成しました。現時点ではソースコードを入手できないので、私が行ったことを実装する方法を説明します。

MyListener1) リッスンするイベント タイプをインターフェイスにリファクタリングする

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

登録方法を次のように変更します

public void addListener(MyListener listener)

2) コンテキスト内の関連するすべてのリスナーを検索する Spring ヘルパー クラスを作成し、見つかったリスナーごとに maintainer#addListener を呼び出します。から始めて、すべての Bean がインスタンス化された後に Bean を登録するために(または)BeanFilteringSupportも実装します。BeanPostProcessorApplicationListener

于 2008-09-16T18:05:30.113 に答える
0

回答ありがとうございます。まず、すべての回答について簡単にフォローアップします。
1. (alexvictor) はい、具体的な列挙型を注釈パラメーターとして使用できますが、 java.lang.Enumは使用できません。
2. flicken さんの回答は正しいですが、残念ながら少し怖いです。私は Spring の専門家ではありませんが、この方法 (Spring へのアクセスを容易にするメソッドの作成) を行うことは、MethodInvokingFactoryBeanソリューションと同様に、少しやり過ぎのようです。あなたの時間と労力に心から感謝したいと思います。
3. Phill の回答は少し変わっています (リスナー Bean を注入する代わりに、そのメンテナを注入します!)。この道を行くと思います。

繰り返しになりますが、ご協力いただきありがとうございます。

于 2008-09-17T09:48:20.753 に答える
0

あなたは「... java.lang.Enum を「注釈パラメーターとして使用することはできません...」と言いました。

私はあなたが間違っていると思います。私は最近、次のようなプロジェクトで使用しました:

public @interface MyAnnotation {
    MyEnum value();
}
于 2008-09-16T14:46:54.867 に答える