Перейти к основному содержимому

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

· 5 мин. чтения

1. Введение

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

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

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

2. Немного фона

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

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

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

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

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

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

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

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

2.3. JMS

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

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

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

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

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

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

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

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

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

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

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

И внедрение зависимостей, и @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 , а не <activation-config-property> .

@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 .