Beispiele: PolicyEventPublisherBean (Publisher), PolicyDocumentGenerationMDB +
CustomerNotificationMDB (zwei unabhaengige Abonnenten), beide novaris-notification-jms.
PolicyEventPublisherBean.publish(...) weiss nichts von seinen Abonnenten - es sendet
einfach auf das Topic jms/novaris/policyEventsTopic. Wie viele Abonnenten es gibt und was
sie mit der Nachricht tun, ist dem Publisher voellig gleichgueltig; genau diese
Entkopplung ist der Sinn von Publish/Subscribe. In diesem Projekt gibt es aktuell zwei
Abonnenten - PolicyDocumentGenerationMDB (Dokumentenerzeugung) und
CustomerNotificationMDB (Kundenbenachrichtigung) - ein drittes System koennte jederzeit
hinzukommen, ohne dass am Publisher irgendetwas geaendert werden muesste.
Eine nicht-dauerhafte ("non-durable") Subscription existiert nur, solange die Consumer-Verbindung aktiv ist - ist der Abonnent gerade nicht erreichbar (Neustart, Deployment, Ausfall), gehen in dieser Zeit publizierte Nachrichten fuer ihn unwiederbringlich verloren. Eine dauerhafte ("durable") Subscription dagegen laesst den JMS-Provider Nachrichten fuer diesen Abonnenten zwischenspeichern, bis er wieder verfuegbar ist:
@ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "Durable"),
@ActivationConfigProperty(propertyName = "clientId", propertyValue = "novaris-notification-jms-docgen"),
@ActivationConfigProperty(propertyName = "subscriptionName", propertyValue = "policy-document-generation"),
Die Subscription wird durch die Kombination aus clientId und subscriptionName
identifiziert - nicht durch die Bean-Klasse. Beide Werte muessen ueber
Neustarts/Deployments hinweg stabil bleiben, sonst legt der Provider eine neue (leere)
Subscription an, statt die bestehende (mit ihren aufgestauten Nachrichten) wiederzuverwenden.
PolicyDocumentGenerationMDB und CustomerNotificationMDB verwenden bewusst
unterschiedliche clientId-Werte, siehe deren Javadoc.
Ein Topic kann Nachrichten unterschiedlichster Art fuehren - hier: POLICY_ISSUED und
CLAIM_REGISTERED (siehe PolicyEventTypes). Nicht jeder Abonnent interessiert sich fuer
alles. Ein Message-Selektor ist ein SQL-92-aehnlicher Filterausdruck auf
Message-Properties, den der JMS-Provider vor der Zustellung auswertet:
// PolicyDocumentGenerationMDB - nur Policenausstellungen
messageSelector = "eventType = 'POLICY_ISSUED'"
// CustomerNotificationMDB - Policenausstellungen UND Schadensmeldungen
messageSelector = "eventType = 'POLICY_ISSUED' OR eventType = 'CLAIM_REGISTERED'"
Beide Selektoren werten dieselbe Message-Property eventType aus, die
PolicyEventPublisherBean explizit setzt:
message.setStringProperty("eventType", eventType);
Wichtig: der Selektor prueft eine Property, nicht den Java-Typ der deserialisierten
Payload - genau deshalb spiegelt der Publisher eventType sowohl als Property als auch als
Feld im PolicyEventMessage-Objekt selbst (siehe dessen Javadoc fuer die volle Begruendung).
Ein Consumer mit nicht passendem Selektor bekommt die Nachricht gar nicht erst zugestellt -
er muss sie nicht empfangen und wieder verwerfen, der Provider filtert vorher.
NotificationTopicFanoutTest (novaris-notification-jms) beweist das Zusammenspiel gegen
einen echten eingebetteten Broker: dieselbe POLICY_ISSUED-Nachricht erreicht beide
Abonnenten, eine CLAIM_REGISTERED-Nachricht dagegen nur den
Customer-Notification-Abonnenten (dessen Selektor beide Typen zulaesst) - der
Document-Generation-Abonnent bekommt sie gar nicht erst zugestellt. Das ist der Kern von
selektivem Publish/Subscribe in einem einzigen, beobachtbaren Test.