«1. Введение

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

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

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

2. Немного предыстории

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

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

Обмен сообщениями — это механизм связи. Используя обмен сообщениями, программы могут обмениваться данными, даже если они написаны на разных языках программирования или находятся в разных операционных системах.

Он предлагает слабосвязанное решение; ни производитель, ни потребитель информации не должны знать подробности друг о друге.

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

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

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

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

2.3. JMS

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

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

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

MDB — это компонент, вызываемый контейнером каждый раз, когда сообщение поступает в систему обмена сообщениями. В результате это событие запускает код внутри этого компонента.

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

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

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

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

  1. It doesn’t exist on the container
  2. created and ready to receive messages

Зависимости, если они есть, внедряются сразу после создания 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, а не \u003cactivation- конфигурационное свойство\u003e.

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

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

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

4.2. Создание производителя

Как описано в разделе 2.1, сервисы производителя и потребителя полностью независимы и даже могут быть написаны на разных языках программирования!

Мы будем создавать наши сообщения, используя сервлеты 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 — это логическое значение, которое определяет, является ли сеанс частью транзакции или нет.

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

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

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

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

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

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

http://127.0.0.1:8080/producer/SendMessageServlet?text=Отправляемый текст ~~ ~ Кроме того, сервлет отправляет «Hello World» в очередь, если мы не отправляем никаких параметров, как в http://127.0.0.1:8080/producer/SendMessageServlet.

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

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

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

Как всегда код закончился на GitHub.

«