Руководство по компонентам, управляемым сообщениями, в EJB

Руководство по бинам, управляемым сообщениями в EJB

1. Вступление

Проще говоря, Enterprise JavaBean (EJB) - это компонент JEE, который работает на сервере приложений.

В этом руководстве мы обсудим компоненты, управляемые сообщениями (MDB), отвечающие за обработку сообщений в асинхронном контексте.

MDB являются частью JEE, начиная со спецификации EJB 2.0; EJB 3.0 introduced the use of annotations, что упрощает создание этих объектов. Здесь мы сосредоточимся на аннотациях.

2. Некоторый Фон

Прежде чем мы углубимся в детали компонентов, управляемых сообщениями, давайте рассмотрим некоторые концепции, связанные с обменом сообщениями.

2.1. обмен сообщениями

Обмен сообщениями - это механизм общения. By using messaging, programs can exchange data even if they’re written in different program languages or reside in different operational systems.с

Он предлагает слабосвязанное решение; neither the producer or the consumer of the information need to know details about each other.

Поэтому их даже не нужно одновременно подключать к системе обмена сообщениями (асинхронная связь).

2.2. Синхронная и асинхронная связь

Во время синхронной связи запрашивающая сторона ждет, пока ответ не вернется. В то же время процесс запроса остается заблокированным.

С другой стороны, при асинхронном взаимодействии запрашивающая сторона инициирует операцию, но не блокируется ею; запрашивающий может перейти к другим задачам и получить ответ позже.

2.3. JMS

Java Message Services («JMS») - это Java API, поддерживающий обмен сообщениями.

JMS предоставляет одноранговые и публиковать / подписывать модели обмена сообщениями.

3. Бобы, управляемые сообщениями

An MDB is a component invoked by the container every time a message arrives on the messaging system. В результате это событие запускает код внутри этого bean-компонента.

Мы можем выполнять множество задач внутри метода MDBonMessage(), начиная с отображения полученных данных в браузере или анализа и сохранения их в базе данных.

Другой пример - отправка данных в другую очередь после некоторой обработки. Все сводится к нашим бизнес-правилам.

3.1. Жизненный цикл компонентов, управляемых сообщениями

MDB имеет только два состояния:

  1. Его нет в контейнере

  2. создан и готов к приему сообщений

Зависимости, если они есть, вводятся сразу после создания MDB.

Чтобы выполнить инструкции перед получением сообщений, нам нужно аннотировать метод с помощью@javax.ejb.PostConstruct.

И внедрение зависимостей, и выполнение@javax.ejb.PostConstruct происходят только один раз.

После этого MDB готов к приему сообщений.

3.2. Сделка

Сообщение может быть доставлено в MDB в контексте транзакции.

Это означает, что все операции в методеonMessage() являются частью одной транзакции.

Поэтому, если произойдет откат, система сообщений повторно доставит данные.

4. Работа с объектами, управляемыми сообщениями

4.1. Создание потребителя

Чтобы создать компонент, управляемый сообщениями, мы используем аннотацию@javax.ejb.MessageDriven перед объявлением имени класса.

Чтобы обработать входящее сообщение, мы должны реализовать методonMessage() интерфейса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());
        }
    }
}

Поскольку в этой статье основное внимание уделяется аннотациям, а не дескрипторам .xml, мы будем использовать@ActivationConfigProperty, а не ..

@ActivationConfigProperty - это свойство типа "ключ-значение", представляющее эту конфигурацию. Мы будем использовать два свойства внутриactivationConfig, устанавливая очередь и тип объекта, который будет использовать MDB.

Внутри методаonMessage() мы можем привести параметр сообщения кTextMessage, BytesMessage, MapMessage StreamMessage илиObjectMessage.

Однако в этой статье мы рассмотрим только содержание сообщения в стандартном выводе.

4.2. Создание продюсера

Как описано в разделе 2.1,producer and consumer services are completely independent and can even be written in different programming languages!

Мы будем создавать наши сообщения с помощью сервлетов Java:

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

После получения экземпляровConnectionFactory иQueue мы должны создатьConnection иSession.

Чтобы создать сеанс, мы вызываем методcreateSession.

Первый параметр вcreateSession - этоboolean, который определяет, является ли сеанс частью транзакции или нет.

Второй параметр используется только тогда, когда первый равенfalse. Он позволяет нам описать метод подтверждения, который применяется к входящим сообщениям и принимает значенияSession.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE иSession.DUPS_OK_ACKNOWLEDGE.

Теперь мы можем запустить соединение, создать текстовое сообщение на объекте сеанса и отправить наше сообщение.

Потребитель, привязанный к той же очереди, получит сообщение и выполнит свою асинхронную задачу.

Кроме того, помимо поиска объектовJNDI, все действия в нашем блоке try-with-resources гарантируют, что соединение будет закрыто, еслиJMSException обнаруживает ошибку, например, пытается подключиться к несуществующей очереди или указав неправильный номер порта для подключения.

5. Тестирование компонента, управляемого сообщениями

Отправьте сообщение через методGET наSendMessageServlet, как в:

Кроме того, сервлет отправляет“Hello World” в очередь, если мы не отправляем никаких параметров, как вhttp://127.0.0.1:8080/producer/SendMessageServlet.

6. Заключение

Бины, управляемые сообщениями, позволяют легко создавать приложения на основе очередей.

Следовательно,MDBs allow us to decouple our applications into smaller services with localized responsibilities, что позволяет создать гораздо более модульную и инкрементную систему, которая может восстанавливаться после сбоев системы.

Как всегда, кодover on GitHub.