Una guida ai fagioli guidati dai messaggi in EJB

1. Introduzione

In poche parole, un Enterprise JavaBean (EJB) è un componente JEE che viene eseguito su un server delle applicazioni.

In questo tutorial, discuteremo Message Driven Beans (MDB), responsabile della gestione dell'elaborazione dei messaggi in un contesto asincrono.

Gli MDB fanno parte di JEE dalla specifica EJB 2.0; EJB 3.0 ha introdotto l'uso delle annotazioni , rendendo più semplice la creazione di quegli oggetti. Qui ci concentreremo sulle annotazioni.

2. Qualche sfondo

Prima di immergerci nei dettagli di Message Driven Beans, esaminiamo alcuni concetti relativi alla messaggistica.

2.1. Messaggistica

La messaggistica è un meccanismo di comunicazione. Utilizzando la messaggistica, i programmi possono scambiare dati anche se sono scritti in linguaggi di programma diversi o risiedono in sistemi operativi diversi.

Offre una soluzione liberamente accoppiata; né il produttore né il consumatore delle informazioni hanno bisogno di conoscere i dettagli l'uno dell'altro .

Pertanto, non devono nemmeno essere collegati contemporaneamente al sistema di messaggistica (comunicazione asincrona).

2.2. Comunicazione sincrona e asincrona

Durante la comunicazione sincrona, il richiedente attende fino a quando non viene restituita la risposta. Nel frattempo, il processo del richiedente rimane bloccato.

Nella comunicazione asincrona, invece, il richiedente avvia l'operazione ma non ne viene bloccato; il richiedente può passare ad altre attività e ricevere la risposta in un secondo momento.

2.3. JMS

Java Message Services ("JMS") è un'API Java che supporta la messaggistica.

JMS fornisce modelli di messaggistica peer to peer e di pubblicazione / sottoscrizione.

3. Message Driven Beans

Un MDB è un componente richiamato dal contenitore ogni volta che un messaggio arriva sul sistema di messaggistica. Di conseguenza, questo evento attiva il codice all'interno di questo bean.

Possiamo eseguire molte attività all'interno di un metodo MDB onMessage () , poiché mostra i dati ricevuti su un browser o li analizza e li salva su un database.

Un altro esempio è l'invio di dati a un'altra coda dopo un'elaborazione. Dipende tutto dalle nostre regole aziendali.

3.1. Ciclo di vita dei fagioli basato sui messaggi

Un MDB ha solo due stati:

  1. Non esiste sul contenitore
  2. creato e pronto per ricevere messaggi

Le dipendenze, se presenti, vengono iniettate subito dopo la creazione dell'MDB.

Per eseguire le istruzioni prima di ricevere i messaggi, dobbiamo annotare un metodo con @ javax.ejb. PostConstruct .

Sia l' inserimento delle dipendenze che @ javax.ejb. L' esecuzione di PostConstruct avviene solo una volta.

Dopodiché, l'MDB è pronto per ricevere messaggi.

3.2. Transazione

Un messaggio può essere consegnato a un MDB all'interno di un contesto di transazione.

Significa che tutte le operazioni all'interno del metodo onMessage () fanno parte di una singola transazione.

Pertanto, se si verifica un rollback, il sistema di messaggi riconsegna i dati.

4. Lavorare con i fagioli guidati dai messaggi

4.1. Creare il consumatore

Per creare un bean Message Driven, usiamo l' annotazione @ javax.ejb.MessageDriven prima della dichiarazione del nome della classe.

Per gestire il messaggio in arrivo, dobbiamo implementare il metodo onMessage () dell'interfaccia MessageListener :

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

Poiché questo articolo si concentra sulle annotazioni anziché sui descrittori .xml, utilizzeremo @ActivationConfigProperty anziché .

@ActivationConfigProperty è una proprietà valore-chiave che rappresenta tale configurazione. Useremo due proprietà all'interno di activationConfig , impostando la coda e il tipo di oggetto che l'MDB consumerà.

All'interno del metodo onMessage () possiamo eseguire il cast del parametro del messaggio su TextMessage, BytesMessage, MapMessage StreamMessage o ObjectMessage .

Tuttavia, per questo articolo, esamineremo solo il contenuto del messaggio sull'output standard.

4.2. Creazione del produttore

Come spiegato nella sezione 2.1, i servizi produttore e consumatore sono completamente indipendenti e possono anche essere scritti in diversi linguaggi di programmazione !

Produrremo i nostri messaggi utilizzando Java Servlet:

@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  message: " + e.getMessage()); } res.getWriter() .println("Message sent: " + text); }

Dopo aver ottenuto le istanze ConnectionFactory e Queue , è necessario creare una connessione e una sessione .

Per creare una sessione, chiamiamo il metodo createSession .

The first parameter in createSession is a boolean which defines whether the session is part of a transaction or not.

The second parameter is only used when the first is false. It allows us to describe the acknowledgment method that applies to incoming messages and takes the values of Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE and Session.DUPS_OK_ACKNOWLEDGE.

We can now start the connection, create a text message on the session object and send our message.

A consumer, bound to the same queue will receive a message and perform its asynchronous task.

Also, apart from looking up JNDI objects, all actions in our try-with-resources block make sure the connection is closed if JMSException encounters an error, such as trying to connect to a non-existing queue or specifying a wrong port number to connect.

5. Testing the Message Driven Bean

Send a message through the GET method on SendMessageServlet, as in:

//127.0.0.1:8080/producer/SendMessageServlet?text=Text to send

Also, the servlet sends “Hello World” to the queue if we don't send any parameters, as in //127.0.0.1:8080/producer/SendMessageServlet.

6. Conclusion

Message Driven Beans allow simple creation of a queue based application.

Pertanto, gli MDB ci consentono di disaccoppiare le nostre applicazioni in servizi più piccoli con responsabilità localizzate , consentendo un sistema molto più modulare e incrementale in grado di ripristinare i guasti del sistema.

Come sempre il codice è finito su GitHub.