Um guia para beans orientados a mensagens no EJB

Um guia para beans orientados a mensagens no EJB

1. Introdução

Simplificando, um Enterprise JavaBean (EJB) é um componente JEE que é executado em um servidor de aplicativos.

Neste tutorial, discutiremos Message Driven Beans (MDB), responsável por lidar com o processamento de mensagens em um contexto assíncrono.

Os MDBs fazem parte do JEE desde a especificação EJB 2.0; EJB 3.0 introduced the use of annotations, tornando mais fácil criar esses objetos. Aqui, vamos nos concentrar nas anotações.

2. Alguns antecedentes

Antes de nos aprofundarmos nos detalhes do Message Driven Beans, vamos revisar alguns conceitos relacionados a mensagens.

2.1. Mensagens

Mensagens é um mecanismo de comunicação. By using messaging, programs can exchange data even if they’re written in different program languages or reside in different operational systems.

Ele oferece uma solução fracamente acoplada; neither the producer or the consumer of the information need to know details about each other.

Portanto, eles nem precisam estar conectados ao sistema de mensagens ao mesmo tempo (comunicação assíncrona).

2.2. Comunicação Síncrona e Assíncrona

Durante a comunicação síncrona, o solicitante espera até que a resposta volte. Enquanto isso, o processo do solicitante permanece bloqueado.

Na comunicação assíncrona, por outro lado, o solicitante inicia a operação, mas não é bloqueado por ela; o solicitante pode passar para outras tarefas e receber a resposta mais tarde.

2.3. JMS

O Java Message Services (“JMS”) é uma API Java que suporta mensagens.

O JMS fornece modelos de mensagens ponto a ponto e publicação / assinatura.

3. Message Driven Beans

An MDB is a component invoked by the container every time a message arrives on the messaging system. Como resultado, este evento dispara o código dentro deste bean.

Podemos realizar várias tarefas dentro de um método MDBonMessage(), desde mostrar os dados recebidos em um navegador ou analisá-los e salvá-los em um banco de dados.

Outro exemplo é enviar dados para outra fila após algum processamento. Tudo se resume às nossas regras de negócios.

3.1. Ciclo de vida do Message Driven Beans

Um MDB possui apenas dois estados:

  1. Não existe no contêiner

  2. criado e pronto para receber mensagens

As dependências, se presentes, são injetadas logo após a criação do MDB.

Para executar instruções antes de receber mensagens, precisamos anotar um método com@javax.ejb.PostConstruct.

A injeção de dependência e a execução de@javax.ejb.PostConstruct acontecem apenas uma vez.

Depois disso, o MDB está pronto para receber mensagens.

3.2. Transação

Uma mensagem pode ser entregue a um MDB dentro de um contexto de transação.

O que significa que todas as operações dentro do métodoonMessage() fazem parte de uma única transação.

Portanto, se ocorrer uma reversão, o sistema de mensagens entrega novamente os dados.

4. Trabalhando com Message Driven Beans

4.1. Criando o consumidor

Para criar um Message Driven Bean, usamos a anotação@javax.ejb.MessageDriven antes da declaração do nome da classe.

Para lidar com a mensagem de entrada, devemos implementar o métodoonMessage() da interfaceMessageListener:

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

Como este artigo se concentra em anotações em vez de descritores .xml, usaremos@ActivationConfigProperty em vez de .

@ActivationConfigProperty é uma propriedade de valor-chave que representa essa configuração. Usaremos duas propriedades dentro deactivationConfig, definindo a fila e o tipo de objeto que o MDB consumirá.

Dentro do métodoonMessage(), podemos lançar o parâmetro da mensagem paraTextMessage, BytesMessage, MapMessage StreamMessage ouObjectMessage.

No entanto, para este artigo, veremos apenas o conteúdo da mensagem na saída padrão.

4.2. Criando o produtor

Conforme abordado na seção 2.1,producer and consumer services are completely independent and can even be written in different programming languages!

Vamos produzir nossas mensagens usando 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);
}

Após obter as instânciasConnectionFactoryeQueue, devemos criar aConnectioneSession.

Para criar uma sessão, chamamos o métodocreateSession.

O primeiro parâmetro emcreateSession é umboolean que define se a sessão é parte de uma transação ou não.

O segundo parâmetro é usado apenas quando o primeiro éfalse. Ele nos permite descrever o método de confirmação que se aplica às mensagens de entrada e assume os valores deSession.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGEeSession.DUPS_OK_ACKNOWLEDGE.

Agora podemos iniciar a conexão, criar uma mensagem de texto no objeto da sessão e enviar nossa mensagem.

Um consumidor vinculado à mesma fila receberá uma mensagem e executará sua tarefa assíncrona.

Além disso, além de procurar objetosJNDI, todas as ações em nosso bloco try-with-resources garantem que a conexão seja fechada seJMSException encontrar um erro, como tentar se conectar a uma fila não existente ou especificando um número de porta errado para conectar.

5. Testando o Message Driven Bean

Envie uma mensagem pelo métodoGET emSendMessageServlet, como em:

Além disso, o servlet envia“Hello World” para a fila se não enviarmos nenhum parâmetro, como emhttp://127.0.0.1:8080/producer/SendMessageServlet.

6. Conclusão

O Message Driven Beans permite a criação simples de um aplicativo baseado em fila.

Portanto,MDBs allow us to decouple our applications into smaller services with localized responsibilities, permitindo um sistema muito mais modular e incremental que pode se recuperar de falhas do sistema.

Como sempre, o código éover on GitHub.