Ein Leitfaden für Message Driven Beans in EJB

Ein Leitfaden für Message Driven Beans in EJB

1. Einführung

Einfach ausgedrückt ist eine Enterprise JavaBean (EJB) eine JEE-Komponente, die auf einem Anwendungsserver ausgeführt wird.

In diesem Tutorial werden wir uns mit Message Driven Beans (MDB) befassen, die für die Verarbeitung von Nachrichten in einem asynchronen Kontext verantwortlich sind.

MDBs sind seit der EJB 2.0-Spezifikation Teil von JEE. EJB 3.0 introduced the use of annotations, was das Erstellen dieser Objekte erleichtert. Hier konzentrieren wir uns auf Anmerkungen.

2. Einige Hintergrundinformationen

Bevor wir uns mit den Details zu Message Driven Beans befassen, wollen wir einige Konzepte im Zusammenhang mit Messaging überprüfen.

2.1. Messaging

Messaging ist ein Kommunikationsmechanismus. By using messaging, programs can exchange data even if they’re written in different program languages or reside in different operational systems.

Es bietet eine lose gekoppelte Lösung; neither the producer or the consumer of the information need to know details about each other.

Daher müssen sie nicht einmal gleichzeitig mit dem Nachrichtensystem verbunden sein (asynchrone Kommunikation).

2.2. Synchrone und asynchrone Kommunikation

Während der synchronen Kommunikation wartet der Anforderer, bis die Antwort zurück ist. In der Zwischenzeit bleibt der Anforderungsprozess blockiert.

Bei der asynchronen Kommunikation hingegen initiiert der Anforderer den Vorgang, wird jedoch nicht von ihm blockiert. Der Anforderer kann mit anderen Aufgaben fortfahren und die Antwort später erhalten.

2.3. JMS

Java Message Services („JMS“) ist eine Java-API, die Messaging unterstützt.

JMS bietet Peer-to-Peer- und Publish / Subscribe-Messaging-Modelle.

3. Message Driven Beans

An MDB is a component invoked by the container every time a message arrives on the messaging system. Infolgedessen löst dieses Ereignis den Code in dieser Bean aus.

Wir können viele Aufgaben innerhalb der MDBonMessage()-Methode ausführen, da die empfangenen Daten in einem Browser angezeigt oder analysiert und in einer Datenbank gespeichert werden.

Ein anderes Beispiel ist das Senden von Daten an eine andere Warteschlange nach einer gewissen Verarbeitung. Es kommt alles auf unsere Geschäftsregeln an.

3.1. Message Driven Beans Lifecycle

Eine MDB hat nur zwei Zustände:

  1. Es ist auf dem Container nicht vorhanden

  2. erstellt und bereit, Nachrichten zu empfangen

Die Abhängigkeiten werden, falls vorhanden, direkt nach der Erstellung der MDB eingefügt.

Um Anweisungen auszuführen, bevor Nachrichten empfangen werden, müssen wir eine Methode mit@javax.ejb.PostConstruct versehen.

Sowohl die Abhängigkeitsinjektion als auch die Ausführung von@javax.ejb.PostConstructerfolgen nur einmal.

Danach ist die MDB bereit, Nachrichten zu empfangen.

3.2. Transaktion

Eine Nachricht kann an eine MDB innerhalb eines Transaktionskontexts übermittelt werden.

Dies bedeutet, dass alle Operationen innerhalb deronMessage()-Methode Teil einer einzelnen Transaktion sind.

Wenn daher ein Rollback auftritt, werden die Daten vom Nachrichtensystem erneut bereitgestellt.

4. Arbeiten mit nachrichtengesteuerten Bohnen

4.1. Verbraucher erstellen

Um eine Message Driven Bean zu erstellen, verwenden wir die Annotation@javax.ejb.MessageDrivenvor der Klassennamendeklaration.

Um die eingehende Nachricht zu verarbeiten, müssen wir dieonMessage()-Methode derMessageListener-Schnittstelle implementieren:

@MessageDriven(activationConfig = {
    @ActivationConfigProperty(
      propertyName = "destination",
      propertyValue = "tutorialQueue"),
    @ActivationConfigProperty(
      propertyName = "destinationType",
      propertyValue = "javax.jms.Queue")
})
public class ReadMessageMDB implements MessageListener {

    public void onMessage(Message message) {
        TextMessage textMessage = (TextMessage) message;
        try {
            System.out.println("Message received: " + textMessage.getText());
        } catch (JMSException e) {
            System.out.println(
              "Error while trying to consume messages: " + e.getMessage());
        }
    }
}

Da sich dieser Artikel auf Anmerkungen anstelle von XML-Deskriptoren konzentriert, verwenden wir@ActivationConfigProperty anstelle von .

@ActivationConfigProperty ist eine Schlüsselwerteigenschaft, die diese Konfiguration darstellt. InactivationConfig werden zwei Eigenschaften verwendet, die die Warteschlange und den Objekttyp festlegen, den die MDB verwendet.

Innerhalb der MethodeonMessage() können wir den Nachrichtenparameter inTextMessage, BytesMessage, MapMessage StreamMessage oderObjectMessage umwandeln.

In diesem Artikel wird jedoch nur der Nachrichteninhalt in der Standardausgabe betrachtet.

4.2. Produzenten erstellen

Wie in Abschnitt 2.1 beschrieben,producer and consumer services are completely independent and can even be written in different programming languages!

Wir erstellen unsere Nachrichten mit Java-Servlets:

@Override
protected void doGet(
  HttpServletRequest req,
  HttpServletResponse res)
  throws ServletException, IOException {

    String text = req.getParameter("text") != null ? req.getParameter("text") : "Hello World";

    try (
        Context ic = new InitialContext();

        ConnectionFactory cf = (ConnectionFactory) ic.lookup("/ConnectionFactory");
        Queue queue = (Queue) ic.lookup("queue/tutorialQueue");

        Connection connection = cf.createConnection();
    ) {
        Session session = connection.createSession(
          false, Session.AUTO_ACKNOWLEDGE);
        MessageProducer publisher = session
          .createProducer(queue);

        connection.start();

        TextMessage message = session.createTextMessage(text);
        publisher.send(message);

    } catch (NamingException | JMSException e) {
        res.getWriter()
          .println("Error while trying to send <" + text + "> message: " + e.getMessage());
    }

    res.getWriter()
      .println("Message sent: " + text);
}

Nachdem wir die InstanzenConnectionFactory undQueue erhalten haben, müssen wirConnection undSession erstellen.

Um eine Sitzung zu erstellen, rufen wir die MethodecreateSessionauf.

Der erste Parameter increateSession istboolean, der definiert, ob die Sitzung Teil einer Transaktion ist oder nicht.

Der zweite Parameter wird nur verwendet, wenn der erstefalse ist. Es ermöglicht uns, die Bestätigungsmethode zu beschreiben, die für eingehende Nachrichten gilt und die WerteSession.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE undSession.DUPS_OK_ACKNOWLEDGE annimmt.

Jetzt können wir die Verbindung herstellen, eine Textnachricht für das Sitzungsobjekt erstellen und unsere Nachricht senden.

Ein Verbraucher, der an dieselbe Warteschlange gebunden ist, empfängt eine Nachricht und führt seine asynchrone Aufgabe aus.

Abgesehen von der Suche nachJNDI-Objekten stellen alle Aktionen in unserem Try-with-Resources-Block sicher, dass die Verbindung geschlossen wird, wennJMSException auf einen Fehler stößt, z. B. beim Versuch, eine Verbindung zu einer nicht vorhandenen Warteschlange herzustellen oder Angabe einer falschen Portnummer für die Verbindung.

5. Testen der Message Driven Bean

Senden Sie eine Nachricht über dieGET-Methode aufSendMessageServlet, wie in:

Außerdem sendet das Servlet“Hello World” an die Warteschlange, wenn wir keine Parameter senden, wie inhttp://127.0.0.1:8080/producer/SendMessageServlet.

6. Fazit

Message Driven Beans ermöglichen die einfache Erstellung einer warteschlangenbasierten Anwendung.

DaherMDBs allow us to decouple our applications into smaller services with localized responsibilities, was ein viel modulareres und inkrementelleres System ermöglicht, das sich von Systemfehlern erholen kann.

Wie immer lautet der Codeover on GitHub.