Unternehmensanwendung für die Verwendung von JMS entwerfen
Beim Entwerfen einer Unternehmensanwendung für die direkte Verwendung der JMS-API für das asynchrone Messaging sind zahlreiche Punkte zu beachten.
Vorgehensweise
- Für das Messaging sollten Sie Anwendungsprogramme schreiben, die nur Referenzen auf die
im Sun-Paket
javax.jms
definierten Schnittstellen verwenden. JMS definiert eine generische Ansicht einer Nachrichtenübertragung, die dem zugrunde liegenden Transportmechanismus zugeordnet ist. Eine Unternehmensanwendung, die JMS verwendet, nutzt die folgenden im Sun-Paket javax.jms definierten Schnittstellen:
- Connection
- Ermöglicht den Zugriff auf den zugrunde liegenden Transportmechanismus und wird für das Erstellen von Sitzungen verwendet.
- Session
- Stellt einen Kontext für das Produzieren und Konsumieren von Nachrichten bereit, der auch die Methoden für das Erstellen von MessageProducers und MessageConsumers beinhaltet.
- MessageProducer
- Wird für das Senden von Nachrichten verwendet.
- MessageConsumer
- Wird für das Empfangen von Nachrichten verwendet.
Die generischen JMS-Schnittstellen werden für die Optionen Punkt-zu-Punkt und Publish/Subscribe wie folgt klassifiziert.Tabelle 1. Punkt-zu-Punkt- und Publish/Subscribe-Versionen der gemeinsamen JMS-Schnittstellen. In der ersten Spalte dieser Tabelle sind die allgemeinen JMS-Schnittstellen aufgelistet, in der zweiten Spalte die entsprechenden Punkt-zu-Punkt-Schnittstellen und in der dritten Spalte die entsprechenden Publish/Subscribe-Schnittstellen. Gemeinsame JMS-Schnittstellen Punkt-zu-Punkt-Schnittstellen Publish/Subscribe-Schnittstellen ConnectionFactory QueueConnectionFactory TopicConnectionFactory Connection QueueConnection TopicConnection Destination Queue Topic Session QueueSession, TopicSession, MessageProducer QueueSender TopicPublisher MessageConsumer QueueReceiver,
QueueBrowserTopicSubscriber Weitere Informationen zur Verwendung dieser JMS-Schnittstellen finden Sie in der Dokumentation zu Java™ Message Service und im Abschnitt Using Java des Information Center von IBM MQ.
Der Abschnitt "Java Message Service (JMS) Requirements" der J2EE-Spezifikation enthält eine Liste der Methoden, die in Web-Containern und EJB-Containern nicht aufgerufen werden dürfen:javax.jms.Session method setMessageListener javax.jms.Session method getMessageListener javax.jms.Session method run javax.jms.QueueConnection method createConnectionConsumer javax.jms.TopicConnection method createConnectionConsumer javax.jms.TopicConnection method createDurableConnectionConsumer javax.jms.MessageConsumer method getMessageListener javax.jms.MessageConsumer method setMessageListener javax.jms.Connection setExceptionListener javax.jms.Connection stop javax.jms.Connection setClientID
Diese Methodeneinschränkung wird in WebSphere Application Server umgesetzt, indem eine Ausnahme des Typs javax.jms.IllegalStateException ausgelöst wird.
- Anwendungen verweisen auf JMS-Ressourcen, die als verwaltete Objekte in WebSphere Application
Server vordefiniert sind.
Details der von Unternehmensanwendungen verwendeten JMS-Ressourcen sind in WebSphere Application Server definiert und werden von der Verwaltungsunterstützung von WebSphere in den JNDI-Namespace eingebunden. Eine Unternehmensanwendung kann diese Objekte aus dem JNDI-Namespace abrufen und verwenden, ohne Informationen zu ihrer Implementierung zu haben. Die macht Änderungen der von den JMS-Ressourcen definierten zugrunde liegenden Messaging-Architektur möglich, ohne die Unternehmensanwendung ändern zu müssen.
Tabelle 2. JMS-Ressourcen für Punkt-zu-Punkt- und Publish/Subscribe-Messaging. In der ersten Spalte dieser Tabelle sind die JMS-Ressourcen für Punkt-zu-Punkt-Messaging und in der zweiten Spalte JMS-Ressourcen für Publish/Subscribe aufgelistet. Punkt-zu-Punkt Publish/Subscribe ConnectionFactory (oder QueueConnectionFactory)
QueueConnectionFactory (oder TopicConnectionFactory)
TopicEine Verbindungsfactory wird verwendet, um Verbindungen zwischen dem JMS-Provider und dem Messaging-System zu erstellen. Sie kapselt die Konfigurationsparameter, die zum Erstellen von Verbindungen erforderlich sind.
- Der Anwendungsserver fasst Verbindungen und Sitzungen mit dem JMS-Provider zu Pools zusammen, um die Leistung zu verbessern. Sie müssen die für Ihre Anwendungen erforderlichen Eigenschaften der Verbindungs- und Sitzungspools konfigurieren, damit das Verbindungs- und Sitzungsverhalten Ihren Vorstellungen entspricht.
- Anwendungen dürfen JMS-Verbindungen, Sitzungen, Erzeuger und Konsumenten nicht zwischenspeichern. WebSphere Application
Server schließt diese Objekte, wenn eine Bean oder ein Servlet beendet wird, und jeder
Versuch, ein zwischengespeichertes Objekt zu verwenden, schlägt mit einer Ausnahme des Typs
javax.jms.IllegalStateException fehl.
Zur Verbesserung der Leistung können Anwendungen JMS-Objekte zwischenspeichern, die über JNDI gesucht wurden. Eine EJB oder ein Servlet muss eine JMS-Verbindungsfactory nur ein einziges Mal suchen, aber die Methode "createConnection" bei jeder Instanziierung aufrufen. Aufgrund der Auswirkungen des Poolings auf Verbindungen und Sitzungen mit dem JMS-Provider dürfte die Leistung nicht beeinträchtigt werden.
- Ein nicht permanenter Subskribent kann nur in dem Transaktionskontext (z. B. einem globalen oder nicht angegebenen Transaktionskontext) angegeben werden, der bei der Erstellung des Subskribenten vorhanden war.
- Permanente Subskriptionen mit dem Standard-Messaging-Provider. Mit einer permanenten
Subskription für ein JMS-Topic erhält ein Subskribent
eine Kopie aller Nachrichten, die für dieses Topic veröffentlicht werden, selbst wenn der Subskribent
in dieser Zeit nicht mit dem Server verbunden ist. Deshalb können Subskribentenanwendungen für längere Zeiten getrennt vom Server arbeiten und dann erneut eine Verbindung
zum Server aufbauen und die Nachrichten verarbeiten, die in ihrer Abwesenheit veröffentlicht wurden.
Wenn eine Anwendung eine permanente Subskription erstellt, wird sie der Laufzeitliste hinzugefügt, die
Administratoren in der Administrationskonsole anzeigen und bearbeiten können.Jede permanente Subskription erhält eine eindeutige ID im Format clientID##subName. Die Parameter sind im Folgenden erläutert:
- clientID
- Die Client-ID, die verwendet wird, um eine Verbindung und ihre Objekte den Nachrichten zuzuordnen, die für Anwendungen (als Clients des JMS-Providers) verwaltet werden. Verwenden Sie eine Namenskonvention, die die Identifizierung der Anwendungen vereinfacht für den Fall, dass Sie die permanenten Subskriptionen für die Laufzeitverwaltung den zugehörigen Anwendungen zuordnen müssen.
- subName
- Der Subskriptionsname, der eine permanente Subskription für die angegebene Client-ID eindeutig kennzeichnet.
Für dauerhafte Subskriptionen, die von MDBs erstellt werden, werden diese Werte in der JMS-Aktivierungsspezifikation gesetzt. Für andere dauerhafte Subskriptionen wird die Client-ID in der JMS-Verbindungsfactory und der Subskriptionsname mit der Operation createDurableSubscriber von der Anwendung gesetzt.
Zum Erstellen einer dauerhaften Subskription für ein Topic verwendet eine Anwendung die in der JMS-API definierte Operation createDurableSubscriber:public TopicSubscriber createDurableSubscriber(Topic topic, java.lang.String subName, java.lang.String messageSelector, boolean noLocal) throws JMSException
- topic
- Der Name des zu subskribierenden JMS-Topic. Dies ist der Name eines Objekts, das die Schnittstellen javax.jms.Topic unterstützt und beispielsweise bei der Suche eines geeigneten JNDI-Eintrags zurückgegeben wird.
- subName
- Der Name für diese Subskription.
- messageSelector
- Es werden nur Nachrichten mit Eigenschaften, die dem Nachrichtenselektorausdruck entsprechen, an Konsumenten zugestellt. Nullwerte und leere Zeichenfolgen zeigen an, dass alle Nachrichten zugestellt werden sollen.
- noLocal
- Wenn diese Einstellung auf truegesetzt ist, wird die Zustellung von Nachrichten verhindert, die in derselben Verbindung veröffentlicht werden, die der permanente Subskribent verwendet.
Anwendungen können die Operation createDurableSubscriber, die nur die Parameter topic und subName akzeptiert, in einem Format mit zwei Argumenten verwenden. Dieser alternative Aufruf ruft die Version mit vier Argumenten, wie zuvor gezeigt, direkt auf, setzt aber messageSelector auf null (sodass alle Nachrichten zugestellt werden) und noLocal auf "false" (sodass in der Verbindung veröffentlichte Nachrichten zugestellt werden). Beispiel: Sie möchten eine dauerhafte Subskription für das Topic myTopic mit dem Subskriptionsnamen mySubscription erstellen:session.createDurableSubscriber(myTopic,"mySubscription");
Falls die Operation "createDurableSubscription" fehlschlägt, löst sie eine JMS-Ausnahme mit einer Nachricht und einer verknüpften Ausnahme aus, die nähere Einzelheiten zur Fehlerursache liefern.
Zum Löschen einer permanenten Subskription verwendet eine Anwendung die in der JMS-API definierte Operation "unsubscribe".
Im normalen Betrieb kann jeweils nur ein Subskribent für eine permanente Subskription aktiv (verbunden) sein. Die Subskribentenanwendung kann jedoch für Failover und Lastausgleich in einem geklonten Anwendungsserver ausgeführt werden. In diesem Fall ist die Einschränkung auf "einen aktiven Subskribenten" aufgehoben, damit eine gemeinsam genutzte Subskription mehrere Konsumenten gleichzeitig haben kann.
Nähere Informationen zur Verwendung permanenter Subskriptionen in Anwendungen finden Sie im Abschnitt "Using Durable Subscriptions" der JMS-Spezifikation.
- Entscheiden Sie, welche Nachrichtenselektoren erforderlich sind. Mit dem JMS-Mechanismus für Nachrichtenselektoren können Sie eine Untergruppe von Nachrichten in einer Warteschlange auswählen, die dann von einem receive-Aufruf zurückgegeben wird. Der Selektor kann sich auf Felder im JMS-Nachrichtenkopf und Felder in den Nachrichteneigenschaften beziehen.
- Aktionen für empfangene Nachrichten. Wenn Nachrichten empfangen werden, können Sie mit diesen gemäß
den Anforderungen der Geschäftslogik in der Anwendung
verfahren. Zu den allgemeinen JMS-Aktionen gehört das Überprüfen des Nachrichtentyps und das Extrahieren des Nachrichteninhaltes. Wenn Sie den
Inhalt aus dem Hauptteil der Nachricht extrahieren möchten, müssen Sie eine Umsetzung
von der generischen Message-Klasse (dem deklarierten Rückgabetyp der receive-Methoden)
auf eine mehr spezifische Unterklasse vornehmen, z. B. auf
TextMessage. Sie sollten es sich zur Gewohnheit machen, die Nachrichtenklasse vor der Umsetzung stets zu testen, um bei unerwarteten
Fehlern gewappnet zu sein.
In diesem Beispiel wird mit dem Operator instanceof überprüft, ob die empfangene Nachricht eine Nachricht des Typs TextMessage ist. Anschließend wird der Nachrichteninhalt durch Umsetzung auf die Unterklasse TextMessage extrahiert.
if ( inMessage instanceof TextMessage ) ... String replyString = ((TextMessage) inMessage).getText();
- JMS-Anwendungen, die den Standard-Messaging-Provider verwenden, können uneingeschränkt auf den Inhalt von Nachrichten zugreifen, die vom integrierten Messaging von WebSphere Application Server Version 5 oder von IBM MQ empfangen werden.
- JMS-Anwendungen können auf die ganze Reihe der JMS_IBM*-Eigenschaften zugreifen. Diese Eigenschaften sind für JMS-Anwendungen nützlich, die vom Standard-Messaging-Provider, vom Standard-Messaging-Provider von Version 5 oder vom IBM MQ-Provider bereitgestellte Ressourcen verwenden.
Für von IBM MQ verarbeitete Nachrichten werden die JMS_IBM*-Eigenschaften entsprechenden MQMD-Feldern (IBM MQ Message Descriptor, IBM MQ-Nachrichtendeskriptor) zugeordnet. Weitere Informationen zu den JMS_IBM*-Eigenschaften und MQMD-Feldern finden Sie im Abschnitt Using Java des Information Center von IBM MQ.
- JMS-Anwendungen können Berichtsnachrichten als eine Form der verwalteten Verarbeitung von Anforderungen/Antworten verwenden, um Produzenten ein Remote-Feedback zu ihren Sendeoperationen und zum Zustand ihrer Nachrichten zu geben. JMS-Anwendungen können alle Berichtsoptionen mit Nachrichteneigenschaften des Typs JMS_IBM_Report_Xxxx anfordern. Nähere Informationen zur Verwendung von JMS-Berichtsnachrichten finden Sie im Artikel JMS-Berichtsnachrichten.
- JMS-Anwendungen können mit der Eigenschaft JMS_IBM_Report_Discard_Msg
steuern, wie eine Anforderungsnachricht verworfen wird, falls Sie nicht an die Zielwarteschlange
zugestellt werden kann.
- MQRO_Dead_Letter_Queue
- Dies ist die Standardeinstellung. Die Anforderungsnachricht wird in die Warteschlange für nicht zustellbare Post geschrieben.
- MQRO_Discard
- Die Anforderungsnachricht wird verworfen. Diese Einstellung wird in der Regel zusammen mit MQRO_Exception_With_Full_Data verwendet, um eine nicht zustellbare Anforderungsnachricht an den Absender zurückzugeben.
- Nachrichten mit einer Listener-Funktion asynchron empfangen. In einem Client ist eine
Alternative zum Aufrufen von QueueReceiver.receive() das Registrieren einer Methode, die automatisch
aufgerufen wird, sobald eine passende Nachricht verfügbar ist. Dies gilt nicht für Servlets und Enterprise-Beans.
Beispiel:
... MyClass listener =new MyClass(); queueReceiver.setMessageListener(listener); //Die Anwendung führt weitere anwendungsspezifische Aktionen aus. ...
Wenn eine Nachricht verfügbar ist, wird sie von der Methode onMessage() am Listener-Objekt abgerufen.import javax.jms.*; public class MyClass implements MessageListener { public void onMessage(Message message) { System.out.println("Die Nachricht lautet: "+message); //Hier folgt die anwendungsspezifische Verarbeitung. ... } }
Beim asynchronen Messaging kann der Anwendungscode keine Ausnahmen abfangen, die von Empfangsfehlern ausgelöst werden, weil der Code keine expliziten Aufrufe für receive()-Methoden enthält. Dieses Problem können Sie lösen, indem Sie einen ExceptionListener registrieren, der eine Instanz einer Klasse ist, die die Methode onException() implementiert. Wenn ein Fehler auftritt, wird diese Methode aufgerufen, wobei die JMSException als einziger Parameter übergeben wird.
Weitere Einzelheiten zur Verwendung von Listenern für den asynchronen Empfang von Nachrichten finden Sie in der Dokumentation zu Java Message Service.
Anmerkung: Wenn Sie keine eigene JMS-Listener-Klasse entwickeln möchten, können Sie auch eine Message-Driven-Bean verwenden. Lesen Sie dazu die Informationen im Artikel Verwendung von MDBs programmieren. Achten Sie bei Ausführung der JMS-Methode receive() von einer serverseitigen Anwendungskomponente aus darauf, ob dieser Aufruf von receive() auf eine Nachricht von einer anderen, in demselben Server implementierten Anwendungskomponente wartet. Eine solche JMS-Methode receive() ist synchron und blockiert die Threads bis zum Empfang einer Antwortnachricht.
Diese Art des Anwendungsentwurfs kann in der Wechselwirkung von Konsument und Produzent dazu führen, dass alle Worker-Threads von der empfangenden Komponente beansprucht werden, die durch das Warten auf Antworten blockiert ist, und dass keine Worker-Threads mehr für die Anwendungskomponente, die die Antwort-JMS-Nachricht generiert, verfügbar sind. Zur Veranschaulichung dieses Problems wollen wir uns ein Servlet und eine MDB vorstellen, die beide in demselben Server implementiert wurden. Wenn das Servlet eine Anforderung zuteilen möchte, sendet es eine Nachricht an eine Warteschlange, die von der MDB betreut wird. (Die vom Servlet produzierten Nachrichten werden somit von der Methode onMessage() der MDB konsumiert.) Anschließend setzt das Servlet ein receive() ab und wartet auf eine Antwort in einer temporären Warteschlange ReplyTo. Die Methode onMessage() der MDB führt eine Datenbankabfrage durch und sendet eine Antwort für das Servlet an die temporäre Warteschlange. Fallen (gemessen an der Anzahl Worker-Threads des Servers) zahlreiche Servletanforderungen auf einmal an, werden wahrscheinlich alle verfügbaren Worker-Threads benötigt, um eine Servletanforderung zuzuteilen, eine Nachricht zu senden und auf eine Antwort zu warten. Der Anwendungsserver gerät so in eine ausweglose Situation, weil keine Threads für die Verarbeitung der anstehenden MDBs übrig sind. Da die Antworten, auf die die Servlets warten, alle blockiert sind, wird der Server blockiert, was wiederum zu einem Anwendungsfehler führen kann.
Lösungsmöglichkeiten:
- Stellen Sie sicher, dass die Anzahl der Worker-Threads (Anzahl Threads pro Serverbereich multipliziert mit der Anzahl von Serverbereichen pro Server) größer als die Anzahl gleichzeitig stattfindender Zuteilungen für die Anwendungskomponente ist, die die Methode receive() ausführt, damit der nachrichtenproduzierenden Komponente stets ein Worker-Thread zugeteilt werden kann.
- Nutzen Sie eine Anwendungstopologie, bei der die empfangende Anwendungskomponente sich in einem anderen Server als die produzierende Anwendungskomponente befindet. Auch bei einem solchen Deployment-Szenario muss die Nutzung von Worker-Threads sorgfältig durchdacht werden; dennoch stellt eine solche Trennung sicher, dass immer Threads vorhanden sind, die nicht von der Komponente, die Nachrichten empfängt, blockiert werden können. Möglicherweise müssen weitere Interaktionen berücksichtigt werden, z. B. ein Anwendungsserver, auf dem mehrere Anwendungen installiert sind.
- Modifizieren Sie Ihre Anwendung so, dass die Nachrichten von einer Clientkomponente empfangen werden, die nicht mit der produzierenden Komponente um Worker-Threads konkurriert. Die Clientkomponente kann Nachrichten auch asynchron (blockierungsfrei) empfangen, was für J2EE-Server nicht zulässig ist. Die zuvor beschriebene Beispielanwendung könnte so modifiziert werden, dass ein Client Nachrichten an eine Warteschlange sendet und dann auf eine Antwort von der MDB wartet.
- Wenn Sie die Authentifizierung mit IBM MQ oder der Unterstützung für das integrierte Messaging der Version 5 verwenden möchten, können Sie keine Benutzer-IDs verwenden, die länger sind als 12 Zeichen. ie Windows NT-Standardbenutzer-ID administrator ist beispielsweise für das interne WebSphere-Messaging nicht gültig, weil sie 13 Zeichen enthält.
- Für die Verwendung von Optionen für Aufrufe des Typs createxxxSessions
gelten die folgenden Punkte gemäß EJB-Spezifikation:
- Die mit createxxxSession übergebene Option transacted wird innerhalb einer globalen Transaktion ignoriert. Alle Arbeitsschritte werden im Rahmen der Transaktion ausgeführt. Außerhalb einer Transaktion wird die Option "transacted" verwendet. Ist diese Option auf true gesetzt, sollte die Anwendung die Ausführung der Arbeitsschritte mit session.commit() und session.rollback() steuern. Ist die Option "transacted" in einem EJB-2.0-Modul auf true gesetzt und außerhalb einer XA-Transaktion definiert, ist die Sitzung Teil der lokalen WebSphere-Transaktion. Das nicht aufgelöste Aktionsattribut der Methode wird auf die JMS-Arbeitsschritte angewendet, vorausgesetzt, diese werden von der Anwendung nicht festgeschrieben oder rückgängig gemacht.
- Clients können Message.acknowledge() nicht zum Bestätigen von Nachrichten verwenden. Wenn der Wert CLIENT_ACKNOWLEDGE im Aufruf von "createxxxSession" übergeben wird, werden Nachrichten automatisch vom Anwenddungsserver bestätigt, und Message.acknowledge() wird nicht verwendet.
- Wenn Sie möchten, dass Ihre Anwendung IBM MQ als
externen JMS-Provider verwendet, senden Sie die Nachrichten in einer containergesteuerten Transaktion.
Wenn Sie IBM MQ als externen JMS-Provider verwenden, können Nachrichten, die in einer containergesteuerten Transaktion gesendet werden, vor der Festschreibung der Transaktion ankommen. Dieser Fall tritt nur ein, wenn Sie IBM MQ als externen JMS-Provider verwenden und Nachrichten in einer benuzterverwalteten Transaktion an eine IBM MQ-Warteschlange senden. Die Nachricht kommt in der Zielwarteschlange an, bevor die Transaktion festgeschrieben ist.
Dieser Fehler ist darauf zurückzuführen, dass der IBM MQ-Ressourcenmanager nicht in der benutzerverwalteten Transaktion registriert ist.
Die Lösung ist die Verwendung einer containergesteuerten Transaktion.


http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=tmj_desap
Dateiname:tmj_desap.html