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 имеет только два состояния:
- Его нет в контейнере
- создано и готово к приему сообщений
Зависимости, если они есть, внедряются сразу после создания 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 .