Einführung in den EventBus

5.444 Aufrufe

Veröffentlicht am

Der EventBus bietet einen Publish/Subscribe-Ereignisdienst für Applikationen an, die innerhalb einer JVM laufen.

Veröffentlicht in: Technologie, Bildung
0 Kommentare
3 Gefällt mir
Statistik
Notizen
  • Als Erste(r) kommentieren

Keine Downloads
Aufrufe
Aufrufe insgesamt
5.444
Auf SlideShare
0
Aus Einbettungen
0
Anzahl an Einbettungen
198
Aktionen
Geteilt
0
Downloads
0
Kommentare
0
Gefällt mir
3
Einbettungen 0
Keine Einbettungen

Keine Notizen für die Folie

Einführung in den EventBus

  1. 1. Einführung in den EventBus Christian Ullenboom
  2. 2. tutego über tutego <ul><li>Inhouse-Schulungen mit individualisierten Inhalten und Terminauswahl </li></ul><ul><li>190 Seminare </li></ul><ul><li>Kernkompetenz Java (60 Themen) </li></ul><ul><li>Europaweit führende Position im Bereich Java-Schulungen </li></ul><ul><li>Hochqualifizierte und zertifizierte Referenten </li></ul><ul><li>Firmengründung 1997 durch Java Champion Christian Ullenboom </li></ul>
  3. 3. Unsere Themen
  4. 4. Unsere Themen
  5. 5. Der EventBus <ul><li>Die Idee von EventBus https://eventbus.dev.java.net/ ist schnell in zwei Sätzen beschrieben: </li></ul><ul><ul><li>Biete einen Publish/Subscribe-Ereignisdienst für Applikationen an, die innerhalb einer JVM laufen. </li></ul></ul><ul><ul><li>Anders als JMS funktioniert EventBus nur in einer JVM, aber nicht über Rechnergrenzen. </li></ul></ul><ul><li>EventBus ist Open-Source unter der Apache Lizenz und geht auf eine Idee von Sun, dem InfoBus aus 1998 zurück. </li></ul>
  6. 6. Wo der EventBus vereinfacht <ul><li>Ereignisbehandlung wird üblicherweise über Observer / Observable oder über Listener realisiert. </li></ul><ul><ul><li>Listener sind aber lästig zu schreiben: Man benötigt XXXEventListener Schnittstellen und Implementierungen, addXXXListener() , removeXXXListener() und fireEventListener() Methoden und vielleicht XXXEvent -Klassen. </li></ul></ul><ul><li>EventBus vereinfacht das und mit zwei Typen und drei Methoden ist ein erstes Beispiel programmiert. </li></ul>
  7. 7. Erstes Beispiel <ul><li>import org.bushe.swing.event.*; </li></ul><ul><li>class Observer { </li></ul><ul><li>Observer() { </li></ul><ul><li>EventBus.subscribe (Object.class, new EventSubscriber <Object>(){ </li></ul><ul><li>    @Override public void onEvent ( Object evt ) { </li></ul><ul><li>      System.out.println( evt ); </li></ul><ul><li>} } ); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>public class First { </li></ul><ul><li>public static void main( String args[] ) { </li></ul><ul><li>  new Observer(); </li></ul><ul><li>  EventBus.publish ( &quot;Hallo Welt&quot; ); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  8. 8. Programmerklärung <ul><li>EventBus.publish(Object) sendet ein Ereignis an alle Interessenten aus. </li></ul><ul><ul><li>EventBus.subscribe(Class, EventSubscriber) meldet für einen speziellen Klassentyp einen Listener an. </li></ul></ul><ul><ul><li>Das Besondere: Es ist hierarchisch. Wir senden mit EventBus.publish(&quot;Hallo&quot;) einen String, aber da String eine Unterklasse von Object ist, bekommt unser &quot;Alles&quot;-Listener die Nachricht. </li></ul></ul><ul><li>EventBus.unsubscribe() meldet den Interessenten wieder ab. </li></ul><ul><li>Der EventSubscriber ist generisch deklariert, sodass es bei EventSubscriber<Object> somit onEvent(Object evt) heißt. </li></ul>
  9. 9. Hierarchien <ul><li>Durch die Möglichkeit Event-Hierarchien aufzubauen, ergibt sich eine große Flexibilität. </li></ul><ul><li>So gehorcht Folgendes auf alle IOException -Events: </li></ul><ul><li>EventBus.subscribe( IOException.class , </li></ul><ul><li> new EventSubscriber(){ … }); </li></ul><ul><li>EventBus.publish( new FileNotFoundException () ); </li></ul><ul><li>Ist dieses Matchen nicht erwünscht, wähle statt </li></ul><ul><ul><li>EventBus.subscribe() die Methode </li></ul></ul><ul><ul><li>EventBus.subscribeExactly() . </li></ul></ul>
  10. 10. Hierarchien bei Generischen Typen <ul><li>Bei Generics funktioniert ein .class nicht wie erwartet. </li></ul><ul><li>Es liefert </li></ul><ul><ul><li>out.println( new Holder<String>().getClass() ); und </li></ul></ul><ul><ul><li>out.println( new Holder<StringBuffer>().getClass() ); </li></ul></ul><ul><li>immer nur class javax.xml.ws.Holder . </li></ul><ul><li>Was passiert bei folgenden Zeilen? </li></ul><ul><li>EventBus.subscribe( Holder.class, new EventSubscriber()… </li></ul><ul><li>EventBus.publish( new Holder<String>(&quot;String value&quot;) ); </li></ul><ul><li>EventBus.publish( new Holder<Date>( new Date() ) ); </li></ul><ul><li>In beiden Fällen wird der auf Holder interessierte Listener benachrichtigt. </li></ul>
  11. 11. TypeReference für generische Typen <ul><li>Soll eine Trennung aufgrund des generischen Typs stattfinden, lässt sich ein java.lang.reflect.Type anmelden und senden. Der Quellcode komplexer: </li></ul><ul><li>EventBus.subscribe( new TypeReference<Holder<Date>>(){}.getType(), </li></ul><ul><li> new EventSubscriber<Object>() { </li></ul><ul><li> @Override public void onEvent( Object evt ) { </li></ul><ul><li>     System.out.println( ((Holder)evt).value ); </li></ul><ul><li> } } ); </li></ul><ul><li>EventBus.publish( new TypeReference<Holder<String>>(){}.getType(), </li></ul><ul><li> new Holder<String>(&quot;String value&quot;) ); </li></ul><ul><li>EventBus.publish( new TypeReference<Holder<Date>>(){}.getType(), </li></ul><ul><li> new Holder<Date>( new Date() ) ); </li></ul><ul><li>Jetzt wird nur noch das Datum empfangen und auf dem Bildschirm erscheint etwa: „Thu Mar 26 14:28:15 CET 2009“. </li></ul>
  12. 12. Topics <ul><li>Im Regelfall sind nicht jeder Interessent an allen Ereignissen interessiert. </li></ul><ul><li>Man kann nun verschiedene Ereignistypen definieren, doch wenn man etwa Strings verschicken möchte, ist es lästig, diesen String extra in ein Ereignisobjekt zu verpacken. </li></ul><ul><li>Die Lösung sind Topics, also bestimmte Themen, zu denen man sich anmelden kann und zu denen man schicken kann. </li></ul><ul><ul><li>So können Strings problemlos an die Topic „Statuszeile“ und „Fehlermeldungen“ geschickt werden. </li></ul></ul>
  13. 13. EventSubscriber und EventTopicSubscriber <ul><li>Es ändern sich in der API zwei Dinge: </li></ul><ul><ul><li>Bei publish() ist der Topic anzugeben, </li></ul></ul><ul><ul><li>bei subscribe() ist statt einem EventSubscriber ein EventTopicSubscriber nötig, da der Listener neben dem Event auch den Topic übergibt. </li></ul></ul>
  14. 14. Beispiel mit Topics <ul><li>EventBus.subscribe( &quot;Error&quot;, new EventTopicSubscriber() </li></ul><ul><li>{ </li></ul><ul><li> @Override public void onEvent(String topic, Object evt) </li></ul><ul><li> { </li></ul><ul><li> System.out.printf( &quot;'%s' für Topic '%s'%n&quot;, </li></ul><ul><li> evt, topic ); </li></ul><ul><li> } </li></ul><ul><li>} ); </li></ul><ul><li>EventBus.publish( &quot;Error&quot;, &quot;Hallo Welt&quot; ); </li></ul><ul><li>Das Beispiel liefert 'Hallo Welt' für Topic 'Error' . </li></ul>
  15. 15. Für mehrere Topics anmelden <ul><li>Soll ein EventTopicSubscriber für mehrere Topics angemeldet werden, so kann man natürlich schreiben: </li></ul><ul><li>EventTopicSubscriber ets = ... </li></ul><ul><li>EventBus.subscribe( topic1, ets ); </li></ul><ul><li>EventBus.subscribe( topic2, ets ); </li></ul><ul><li>Eine weitere subscribe() -Methode ist subscribe(java.util.regex.Pattern, EventTopicSubscriber) . </li></ul><ul><ul><li>Schnell sind so Gruppen via Reguläre Ausdrücke erzeugt. </li></ul></ul>
  16. 16. subscribe() mit java.util.regex.Pattern <ul><li>EventBus.subscribe( Pattern.compile( &quot; Error|Warning &quot; ), </li></ul><ul><li>new EventTopicSubscriber() {...} ); </li></ul><ul><li>EventBus.publish( &quot; Error &quot;, &quot;Hallo Welt&quot; ); </li></ul><ul><li>EventBus.publish( &quot; Info &quot;, &quot;Hallo Welt&quot; ); // Kommt nicht an </li></ul><ul><li>EventBus.publish( &quot; Warning &quot;, &quot;Hallo Welt&quot; ); </li></ul>
  17. 17. EventBus und EDT (1/2) <ul><li>Setzt man in die onEvent() -Methode die Anweisung </li></ul><ul><li>System.out.println( Thread.currentThread() ); </li></ul><ul><li>so arbeitet EventBus den Programmcode im AWT Event Thread (EDT) ab. </li></ul><ul><li>Das sieht man an der Ausgabe </li></ul><ul><li>Thread[AWT-EventQueue-0,6,main] </li></ul><ul><li>Das ist sinnvoll für Aktionen an Swing-Komponenten. </li></ul>
  18. 18. EventBus und EDT (2/2) <ul><li>Beispiel: </li></ul><ul><ul><li>Ein beliebiger Thread lädt Daten und möchte nach dem Laden eine Statuszeile aktualisieren. </li></ul></ul><ul><ul><li>Schickt der Thread mit publish() ein Ereignis, wird der Programmcode vom Empfänger im EDT ausgeführt, sodass dort etwa ein setText() auf einem JLabel der Statuszeile erlaubt ist. </li></ul></ul><ul><li>Konsequenz ist, dass der Programmcode schnell sein muss, damit der EDT nicht zu lange blockiert wird. </li></ul><ul><li>Bei nicht-AWT-Anwendungen ist die Abarbeitung im EDT unsinnig. </li></ul>
  19. 19. EventBus und SwingEventService <ul><li>Der EventBus setzt den Programmcode standardmäßig in den EDT, kann ihn aber auch von einem anderen Thread abarbeiten lassen. </li></ul><ul><li>System.out.println( EventBus.getGlobalEventService() ); </li></ul><ul><li>// org.bushe.swing.event.SwingEventService@173a10f </li></ul><ul><li>Standardmäßig nutzt EventBus also intern ein SwingEventService -Objekt. </li></ul>
  20. 20. SwingEventService <ul><li>SwingEventService eventing = new SwingEventService(); </li></ul><ul><li>eventing.subscribe( Object.class, new EventSubscriber(){ </li></ul><ul><li>@Override public void onEvent( Object evt ) { </li></ul><ul><li>System.out.println( evt ); </li></ul><ul><li>} </li></ul><ul><li>} ); </li></ul><ul><li>eventing.publish( &quot;Hallo&quot; ); </li></ul>
  21. 21. [Swing|ThreadSafe]EventService <ul><li>Neben dem SwingEventService gibt es den ThreadSafeEventService für eine Abarbeitung, die nicht im EDT stattfindet. </li></ul><ul><ul><li>Beide implementieren die Schnittstelle EventService . (Genau genommen ist SwingEventService eine Unterklasse von ThreadSafeEventService .) </li></ul></ul><ul><li>EventService eventing = new ThreadSafeEventService(); </li></ul><ul><li>eventing.subsribe(...); </li></ul><ul><li>eventing.publish(...); </li></ul>
  22. 22. *EventService
  23. 23. EventServiceLocator <ul><li>Den EventBus kann man nun so umstellen, dass er standardmäßig den ThreadSafeEventService nutzt. </li></ul><ul><li>Dazu wird intern ein EventServiceLocator eingesetzt. </li></ul><ul><li>out.println( EventBus.getGlobalEventService() ); </li></ul><ul><li>// org.bushe.swing.event.SwingEventService </li></ul><ul><li>out.println( EventServiceLocator.getEventBusService() ); </li></ul><ul><li>// org.bushe.swing.event.SwingEventService </li></ul><ul><li>out.println( EventServiceLocator.getSwingEventService() ); </li></ul><ul><li>// org.bushe.swing.event.SwingEventService </li></ul><ul><li>Der EventServiceLocator verwaltet also zwei unterschiedliche Event-Services. </li></ul>
  24. 24. EventServiceLocator UML
  25. 25. Mit dem EventServiceLocator umbiegen <ul><li>try { </li></ul><ul><li>EventServiceLocator.setEventService( </li></ul><ul><li>EventServiceLocator.SERVICE_NAME_EVENT_BUS, </li></ul><ul><li>new ThreadSafeEventService() ); </li></ul><ul><li>} catch ( EventServiceExistsException e ) { e.printStackTrace(); } </li></ul><ul><li>System.out.println( EventBus.getGlobalEventService() ); </li></ul><ul><li>// org.bushe.swing.event.ThreadSafeEventService </li></ul><ul><li>System.out.println( EventServiceLocator.getEventBusService() ); </li></ul><ul><li>// org.bushe.swing.event.ThreadSafeEventService </li></ul><ul><li>System.out.println( EventServiceLocator.getSwingEventService() ); </li></ul><ul><li>// org.bushe.swing.event.SwingEventService </li></ul><ul><li>Achtung: setEventService() muss an den Anfang bevor ein </li></ul><ul><li>Event je den Bus sieht! </li></ul>
  26. 26. EventServiceLocator (3/3) <ul><li>Wenn man nun Ereignisse über einen „normalen“ Thread bearbeitet haben möchte, schreibt man wie üblich EventBus.publish() / subscribe() . </li></ul><ul><li>Sollen die Eventanweisungen in den EDT, schreibt man </li></ul><ul><ul><li>EventServiceLocator.getSwingEventService().publish() </li></ul></ul><ul><ul><li>EventServiceLocator.getSwingEventService().subscribe() </li></ul></ul>
  27. 27. Hängende Referenzen bei Listenern <ul><li>Ein häufiges Problem bei Listenern insbesondere bei Swing-Anwendungen sind angemeldete Listener, für die der Interessent schon weg ist. Ein Szenario: </li></ul><ul><ul><li>Ein Textfeld einer Maske meldet einen Listener an, um bei Modelländerungen die Daten darstellen zu können. </li></ul></ul><ul><ul><li>Das Model speichert den Listener und indirekt auch eine Referenz auf das Textfeld. </li></ul></ul><ul><ul><li>Die Maske verschwindet, somit auch der Interessent für Modelländerungen. </li></ul></ul><ul><ul><li>Da aber das Model den Listener und indirekt das Textfeld referenziert, kann der GC das Textfeld gar nicht freigeben. </li></ul></ul><ul><ul><li>Daher müssen Listener immer abgemeldet werden, oder...? </li></ul></ul>
  28. 28. EventBus und WeakReference (1/3) <ul><li>Damit Listener bei nicht mehr aktiven Horchern automatisch verschwinden, kann man WeakReference s einsetzen. </li></ul><ul><li>Eine WeakReference ist wie ein Proxy, der ein anderes Objekt ummantelt. Ist die WeakReference die einzige Referenz, die sich für das Objekt interessiert, so kann sie beim nächsten GC das Objekt wegräumen. Der Proxy wird dann ebenfalls nicht mehr benutzt. </li></ul><ul><li>Standardmäßig mantelt die EventBus.subscribe(XXX, EventSubscriber) -Methoden den EventSubscriber in eine WeakReference . </li></ul><ul><ul><li>Wenn es also keinen starken Verweis auf den EventSubscriber mehr von außen gibt, wird der EventBus diesen Listener automatisch abmelden. </li></ul></ul>
  29. 29. EventBus und WeakReference (2/3) <ul><li>public class First </li></ul><ul><li>{ </li></ul><ul><li>First() </li></ul><ul><li>{ </li></ul><ul><li>new Observer(); </li></ul><ul><li>} </li></ul><ul><li>public static void main( String args[] ) </li></ul><ul><li>{ </li></ul><ul><li>  new First(); </li></ul><ul><li>// System.gc(); </li></ul><ul><li>  EventBus.publish( &quot;Hallo Welt&quot; ); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  30. 30. EventBus und WeakReference (3/3) <ul><li>Der Konstruktor erzeugt einen Observer, der aber nicht referenziert wird. Nach dem der Konstruktor abgearbeitet wurde, ist das Exemplar Freiwild für den GC. </li></ul><ul><li>Wenn in main() die Funktion System.gc() aufgerufen wird, wird aufgeräumt. Damit werden die WeakReference s entsorgt, also auch der Listener beim EventBus abgemeldet. </li></ul><ul><li>Ist das System.gc() raus, steht immer noch „Hallo“ auf der Konsole, weil das Objekt noch da ist. </li></ul><ul><li>Soll EventBus keinen WeakReference -Behälter um den Listener bauen, so nutzt man </li></ul><ul><ul><li>subscribeStrongly(XXX, EventSubscriber) bzw. </li></ul></ul><ul><ul><li>subscribeExactlyStrongly(XXX, EventSubscriber) . </li></ul></ul>
  31. 31. Zusammenfassung: EventBus API
  32. 32. Was fehlt noch? <ul><li>EventBus kann die Listener aufzählen. </li></ul><ul><li>EventBus kann Veto. </li></ul><ul><li>Listener können über Annotationen angemeldet werden. </li></ul><ul><li>Wo das Event zuerst gemeldet werden soll kann eine Priorität bestimmen. </li></ul><ul><li>Timer können Events überwachen. </li></ul><ul><li>Events können gechached werden, sodass spätere Anmelder die Events auch bekommen. </li></ul>

×