Frage

Während einfache, Schnittstelle gesteuerte Ereignisbenachrichtigung Frameworks in Java gibt es schon seit präkambrischen Zeiten (z java.beans.PropertyChangeSupport), es wird immer beliebter für Frameworks Annotation gesteuerte Ereignisbenachrichtigung stattdessen zu verwenden.

Ein Beispiel finden Sie unter JBossCache 2.2 . Die Listener-Klasse hat ihre Zuhörer Methoden kommentierten, anstatt auf eine starre Schnittstelle entspricht. Dies ist eher einfacher zu programmieren, und leichter zu lesen, da sie nicht mit leeren Implementierungen Zuhörer Rückrufe zu schreiben haben, dass Sie nicht interessiert sind (und ja, ich weiß, über Hörer Adapter Super).

Hier ist ein Beispiel aus der JBossCache docs:

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

}

Das Problem dabei ist, dass es sehr viel mehr ein langwieriger Prozess, den Rahmen zu schreiben diese Art der Sache zu unterstützen, aufgrund der Annotation-Reflexion Natur davon.

Also, bevor ich die Straße runter laden off einen allgemeinen Rahmen zu schreiben, ich hatte gehofft, dass jemand es bereits getan hatte. Hat jemand kommen über so etwas?

War es hilfreich?

Lösung

Sie können bereits das heute tun mit EventBus .

Beispiel folgend ist von EventBus Erste Führung gestartet. Statusbar, die auf veröffentlichten Veranstaltungen basieren Updates und keine Notwendigkeit statusbar Kontrolle / Widget als Hörer des Verlegers (en) zu registrieren. Ohne EventBus, statusbar müssen als Zuhörer hinzugefügt werden, um viele Klassen. Statusbar kann auch jederzeit erstellt und zerstört werden.

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

Ein ähnliches Projekt ist ELF (Ereignis-Listener Framework) aber es scheint, weniger reif zu sein.

Ich bin die Erforschung zur Zeit über die Ereignisbenachrichtigung Frameworks auf

Andere Tipps

Ich habe http://neoevents.googlecode.com diese Art von Anmerkung basierten Ereignis zu behandeln Handler.

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

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

Es sieht so einfach, wie ich es erwartet hatte, es zu sein. Anmerkungen sind für jeden einzelnen Zuhörer in J2SE zur Verfügung.

Sie nicht für klug kompliziert Fehler. Es scheint mir, dass dies wäre:

  1. Ein Alptraum debuggen
  2. Schwer zu folgen (von einer Wartungs Perspektive oder jemand versucht, etwas 6 Monate auf der ganzen Linie zu ändern)
  3. Voller if (event instanceof NodeCreatedEvent) wie Code. Warum ist dies besser als Subklassen eine adapter Ich habe keine Ahnung!

Das Hauptproblem ich hier sehen, sind die Verfahrensparameter, die die Methoden beschränken kann tatsächlich für die Ereignisse verwendet werden, und es gibt keine Kompilierung-Hilfe für das.

Dies ist, was für Beobachter-Muster-Implementierungen wie das Java-Ereignismodell zu mir Schnittstellen attraktiv macht. Tools wie Eclipse kann Methode Stubs Autogen, so dass Sie nicht die Unterschriften falsch bekommen. In Ihrem Beispiel ist es sehr einfach die falsche Parametertyp zu verwenden und wissen, dass es nie, bis ein Ereignis eintritt (die ein Fehlerfall mehrere Monate auf der ganzen Linie sein könnte)

Eine Sache, die Sie könnten versuchen, sind meine Anmerkungen & Prozessor für Beobachter und Null-Objekt-Implementierungen zu implementieren. Angenommen, Sie haben

package a.b.c;

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

und wollte einen Zuhörer Instanz erstellen. Sie könnten schreiben

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

Um eine Quelle für diese Ereignisse zu erstellen, können Sie schreiben

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
}

Siehe http://code.google.com/p/javadude/wiki/ Anmerkungen wenn Sie interessiert sind. Dann kann man auch einige andere Ideen.

Ich habe auch über einen allgemeinen Anmerkung gesteuerte Ereignis Rahmen denken. Ich mag die durch statische Typisierung erbrachten Leistungen, aber das aktuelle Schnittstelle gesteuerte Ereignismodell ist schmerzhaft (hässlich Code) zu verwenden. Wäre es möglich, eine benutzerdefinierte Anmerkung Prozessor zu verwenden, um einige Compile-Zeit zu tun, überprüft? Das könnte einige der fehlenden „Sicherheit“ helfen hinzufügen, die wir alle zu gewöhnt.

Eine Menge der Fehlerprüfung kann auch zu dem Zeitpunkt erfolgen, dass die Zuhörer „registriert“ mit den Event-Produzenten sind. Somit würde die Anwendung früh ausfallen (wenn die Zuhörer registriert sind), möglicherweise auch bei bei Start-Zeit.

Hier ist ein Beispiel dafür, was der allgemeine Rahmen, den ich mit aussehen könnte liebäugelt habe wie:

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

Der Hersteller verwendet EventSupport, die Reflexion verwendet die Ereignisse aufzurufen. Wie bereits erwähnt, EventSupport könnten einige erste Kontrollen der Vorform, wenn die Ereignisse Zuhörer registriert sind.

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

Hier hat EventSupport eine statische Methode, die Reflexion verwendet, um den Hörer mit dem Event-Produzenten Auto-registrieren. Dadurch entfällt die Notwendigkeit, manuell mit der Ereignisquelle zu registrieren. Ein benutzerdefinierte Annotation Prozessor könnte verwendet werden, um zu bestätigen, dass die @HandlesEventFor Annotation zu einem tatsächlichen Feld des ExampleListener bezieht. Die Anmerkung Prozessor könnte weitere Prüfungen durchführt als auch, wie sichergestellt wird, dass die Event-Handler-Methode Signatur übereinstimmt mit einem der Registrierungsverfahren auf dem ExampleProducer (im Grunde die gleiche Prüfung, die bei der Registrierung Zeit durchgeführt werden konnte) auf.

Was denken Sie? Ist das wert einig Zeit in vollem Umfang zu entwickeln setzen?

Hier ist ein ähnliches Projekt namens 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));
}
}

Ich denke, das sehr einfach zu bedienen ist.

Sie können auch Besuche MBassador Es ist Anmerkung angetrieben, sehr leicht und nutzen schwachen Verweis ( so einfach in Umgebungen zu integrieren, wo Objekte Lifecycle Management durch einen Rahmen wie im Frühling oder guice oder somethign erfolgt).

Es stellt ein Objekt Filtermechanismus (so könnte man zu NodeEvent abonnieren und einige Filter anhängen-Nachricht an eine Reihe von spezifischen Arten der Handhabung beschränken nur). Sie können auch Ihre eigenen Anmerkungen definieren maßgeschneiderte Deklaration Ihrer Handler haben.

Und es ist sehr schnell und ressourceneffizient. Sehen Sie sich diese Benchmark ein Leistungsdiagramm für verschiedene Szenarien zeigt mit Guava oder mbassador.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top