7

Java の単純なインターフェース駆動型のイベント通知フレームワークはカンブリア紀以前から存在していましたが (例: java.beans.PropertyChangeSupport)、代わりにアノテーション駆動型のイベント通知を使用するフレームワークがますます一般的になりつつあります。

例については、JBossCache 2.2を参照してください。リスナー クラスには、厳密なインターフェイスに準拠するのではなく、注釈が付けられたリスナー メソッドがあります。これは、関心のないリスナー コールバックの空の実装を記述する必要がないため、プログラミングがかなり簡単で、読み取りも簡単です (もちろん、リスナー アダプターのスーパークラスについては知っています)。

JBossCache ドキュメントのサンプルを次に示します。

@CacheListener
public class MyListener {
   @CacheStarted
   @CacheStopped
   public void cacheStartStopEvent(Event e) {
         switch (e.getType()) {
            case Event.Type.CACHE_STARTED:
               System.out.println("Cache has started");
               break;    
            case Event.Type.CACHE_STOPPED:    
               System.out.println("Cache has stopped");
               break;    
         }
   }    

   @NodeCreated    
   @NodeRemoved
   @NodeVisited
   @NodeModified
   @NodeMoved
   public void logNodeEvent(NodeEvent ne) {
         log("An event on node " + ne.getFqn() + " has occured");
   }

}

これに関する問題は、フレームワークの注釈反射の性質のために、この種のものをサポートするためにフレームワークを作成することは、非常に複雑なプロセスであることです。

そのため、一般的なフレームワークを書き始める前に、誰かが既にそれを行っていることを期待していました。誰かがそのようなことに出くわしたことがありますか?

4

8 に答える 8

8

これは、 EventBusを使用してすでに実行できます。

次の例は、EventBus Getting Started guideからのものです。発行されたイベントに基づいて更新されるステータスバー。ステータスバー コントロール/ウィジェットをパブリッシャーのリスナーとして登録する必要はありません。EventBus がなければ、多くのクラスにリスナーとしてステータスバーを追加する必要があります。ステータスバーは、いつでも作成および破棄できます。

public StatusBar extends JLabel {
    public StatusBar() {
        AnnotationProcessor.process(this);
    }
    @EventSubscriber(eventClass=StatusEvent.class)
    public void updateStatus(StatusEvent statusEvent) {
        this.setText(statusEvent.getStatusText();
    }
}

同様のプロジェクトにELF (Event Listener Framework)がありますが、あまり成熟していないようです。

私は現在、Publish-Subscribe Event Driven Programming |でイベント通知フレームワークについて研究しています。Kev の Spring vs Java EE Devとフォローアップ記事。

于 2009-12-30T13:23:00.243 に答える
4

私はhttp://neoevents.googlecode.comを作成して、この種のアノテーション ベースのイベント ハンドラーを処理しました。

@actionPerformed
private void onClick() {
    //do something
}

protected void initComponents() {
    JButton button = new JButton("Click me!!!");
    button.addActionListener(new ActionListener(this) );
}

思っていた通りシンプルに見えます。注釈は、J2SE のすべてのリスナーで使用できます。

于 2010-01-10T22:56:12.797 に答える
3

複雑なものを賢いと間違えないでください。これは次のように思われます。

  1. デバッグする悪夢
  2. フォローするのが難しい(メンテナンスの観点から、または6か月後に何かを変更しようとしている人)
  3. if (event instanceof NodeCreatedEvent)同様のコードでいっぱい。なぜこれがサブクラス化よりも優れているadapterのか私にはわかりません!
于 2008-10-07T15:30:14.580 に答える
2

ここで私が目にする主な問題は、どのメソッドをどのイベントに実際に使用できるかを制限するメソッド パラメーターであり、そのためのコンパイル時のヘルプはありません。

これが、Java イベント モデルのようなオブザーバー パターンの実装にとって、インターフェイスが魅力的である理由です。Eclipse のようなツールはメソッド スタブを自動生成できるため、署名を間違えることはありません。あなたの例では、間違ったパラメータータイプを使用するのは非常に簡単で、イベントが発生するまでそれを知ることはできません (これは、数か月後のエラーケースである可能性があります)

あなたが試すかもしれないことの1つは、オブザーバーとnullオブジェクトの実装を実装するための私の注釈とプロセッサーです。あなたが持っていると仮定します

package a.b.c;

public interface SomeListener {
    void fee();
    void fie();
    void fo();
    void fum();
}

リスナーインスタンスを作成したいと考えていました。あなたは書くことができます

package x.y.z;

import a.b.c.SomeListener;
import com.javadude.annotation.Bean;
import com.javadude.annotation.NullObject;

@Bean(nullObjectImplementations = {@NullObject(type = SomeListener.class) })
public class Foo extends FooGen implements SomeListener {
    @Override
    public void fie() {
        // whatever code you need here
    }
}

これらのイベントのソースを作成するには、次のように記述できます。

package a.b.c;

import com.javadude.annotation.Bean;
import com.javadude.annotation.Observer;

@Bean(observers = {@Observer(type = SomeListener.class)})
public class Source extends SourceGen {
    // SourceGen will have add/remove listener and fire methods
    //   for each method in SomeListener
}

興味がある場合は、http://code.google.com/p/javadude/wiki/Annotationsを参照してください。他のアイデアも教えてくれるかもしれません。

于 2008-10-07T15:53:22.583 に答える
1

これはSJESと呼ばれる同様のプロジェクトです。

public class SomeController {

private Calculator c1 = new Calculator();
private Calculator c2 = new Calculator();

public SomeController() {
    c1.registerReceiver(this);
    c2.registerReceiver(this);
    c1.add(10, 10);
    c2.add(20, 20);
}

@EventReceiver(handleFor="c1")
public void onResultC1(Calculator.Event e) {
    System.out.println("Calculator 1 got: " + e.result);
}

@EventReceiver(handleFor="c2")
public void onResultC2(Calculator.Event e) {
    System.out.println("Calculator 2 got: " + e.result);
}

@EventReceiver
public void onResultAll(Calculator.Event e) {
    System.out.println("Calculator got: " + e.result);
}
}

public class Calculator {

private EventHelper eventHelper = new EventHelper(this);

public class Event {

    long result;

    public Event(long result) {
        this.result = result;
    }
}

public class AddEvent extends Event {

    public AddEvent(long result) {
        super(result);
    }
}

public class SubEvent extends Event {

    public SubEvent(long result) {
        super(result);
    }
}

public void unregisterReceiver(Object o) {
    eventHelper.unregisterReceiver(o);
}

public void registerReceiver(Object o) {
    eventHelper.registerReceiver(o);
}

public void add(long a, long b) {
    eventHelper.fireEvent(new AddEvent(a + b));
}

public void sub(long a, long b) {
    eventHelper.fireEvent(new SubEvent(a - b));
}

public void pass(long a) {
    eventHelper.fireEvent(new Event(a));
}
}

とても使いやすいと思います。

于 2010-05-03T16:40:19.583 に答える
1

私は、一般的なアノテーション駆動型のイベント フレームワークについても考えてきました。静的型付けによって得られる利点は気に入っていますが、現在のインターフェイス駆動型のイベント モデルは使いにくいです (醜いコード)。カスタム注釈プロセッサを使用してコンパイル時のチェックを行うことは可能でしょうか? これは、私たちが慣れ親しんできた不足している「安全」を追加するのに役立つかもしれません.

多くのエラー チェックは、リスナーがイベント プロデューサーに「登録」されるときにも実行できます。したがって、アプリケーションは早期に (リスナーが登録されたとき)、おそらく起動時にも失敗します。

これは、私がいじっていた一般的なフレームワークがどのように見えるかの例です。

public class ExampleProducer {

    private EventSupport<ActionEvent> eventSupport;

    public ExampleProducer() {
        eventSupport = new EventSupport<ActionEvent>(this);
    }

    @AddListenersFor(ActionEvent.class)
    public void addActionListener(Object listener)
    {
        eventSupport.addListener(listener);
    }

    @RemoveListenersFor(ActionEvent.class)
    public void removeActionListener(Object listener)
    {
        eventSupport.removeListener(listener);
    }

    public void buttonClicked() {
        eventSupport.fire(new ActionEvent(this, 
                              ActionEvent.ACTION_PERFORMED, "Click"));
    }
   }

プロデューサーはEventSupport、リフレクションを使用してイベントを呼び出す を使用します。前述のようにEventSupport、イベント リスナーが登録されたときにいくつかの初期チェックを実行できます。

public class ExampleListener
{   
  private ExampleProducer submitButton;

  public ExampleListener()
  {
    submitButton = new ExampleProducer();
    EventSupport.autoRegisterEvents(this);
  }

  @HandlesEventFor("submitButton")
  public void handleSubmitButtonClick(ActionEvent event)
  {
    //...some code to handle the event here
  }
}

ここにEventSupportは、リフレクションを使用してリスナーをイベント プロデューサーに自動登録する静的メソッドがあります。これにより、イベント ソースに手動で登録する必要がなくなります。カスタム アノテーション プロセッサを使用して、@HandlesEventForアノテーションが の実際のフィールドを参照していることを検証できますExampleListener。アノテーション プロセッサは、イベント ハンドラー メソッドのシグネチャが の登録メソッドの 1 つと一致することを確認するなど、他のチェックも行うことができますExampleProducer(基本的に、登録時に実行できる同じチェック)。

どう思いますか?これは、完全な開発に時間を割く価値がありますか?

于 2009-05-13T10:39:15.283 に答える
0

MBassadorも確認できます。これはアノテーション駆動型で、非常に軽量で、弱参照を使用します (したがって、オブジェクトのライフサイクル管理が spring や guice などのフレームワークによって行われる環境に簡単に統合できます)。

オブジェクト フィルタリング メカニズムを提供します (したがって、NodeEvent をサブスクライブし、いくつかのフィルターをアタッチして、メッセージ処理を特定の種類のセットのみに制限することができます)。独自の注釈を定義して、ハンドラーの宣言をカスタマイズすることもできます。

また、非常に高速で、リソース効率も優れています。Guava または mbassador を使用したさまざまなシナリオのパフォーマンス グラフを示すこのベンチマークを確認してください。

于 2012-10-23T09:36:44.967 に答える