jms api что такое

Знакомство с JMS 2.0

Не так давно, 12 июня 2013, миру был представлен релиз Java EE 7. Одним из ключевых моментов в этом релизе было появление JMS версии 2.0, которая не обновлялась с 2002 года.

Данный текст является вольным переводом начала статьи Найджела Дикина. Текст предназначен для ознакомления заинтересованного читателя с новым API.

API JMS 1.1 требует для работы достаточно много кода, но успело себя хорошо зарекомендовать, потому, с 2002 года не изменялось. В JMS 2.0 новое API призвано упростить отправку и прием JMS-сообщений. Прежнее API не упраздняется и продолжает работать наравне с новым.

В API JMS 2.0 появились новые интерфейсы: JMSContext, JMSProducer и JMSConsumer.

Отправка JMS

Для сравнения. JMS 1.1:

Отличительной особенностью нового API является то, что его методы бросают RuntimeException — JMSRuntimeException, вместо checked-исключения JMSException. Это дает возможность при желании не обрабатывать JMS-исключения.

Синхронное получение JMS

Сравниваем разницу при синхронном получении сообщений.
JMS 1.1:

Асинхронное получение JMS

В JavaSE, что бы получать сообщения асинхронно, в JMS 1.1 используется следующий код:

В JMS 2.0 это выглядит так:

Вместо MessageConsumer — JMSConsumer. Соединение стартует автоматически.

В Java EE Web или EJB приложениях, как и прежде, надо использовать message-driven bean, вместо метода setMessageListener

Вставка объекта JMSContext в Java EE приложении

В Java EE приложении JMSContext можно вставить посредством аннотации Inject. После вставки JMSContext будет находиться под управлением сервера приложений.

Следующий фрагмент кода позволяет вставлять JMSContext в session bean или сервлет.

Закрытие JMSContext производится автоматически сервером приложений. Если во время запроса выполняется JTA-транзакция, то JMSContext закроется автоматически после коммита, если без транзакции, то закроется в конце запроса.

На этом я решил остановиться. Для ознакомления и начала работы этой информации должно быть достаточно. Много детаей и дополнительной информации тут:
What’s New in JMS 2.0, Part One: Ease of Use
What’s New in JMS 2.0, Part Two—New Messaging Features

Источник

JMS сообщения в Java приложении

JMS (Java Message Service) является стандартом обмена сообщениями между приложениями. Java приложения, выполненные по технологии Java SE (standalone) или Java EE (WEB) могут создавать, отправлять и получать JMS сообщения. Программное обеспечение, используемое для передачи сообщений между приложениями по стандарту JMS, формирует очереди сообщений queue.

Отправка сообщений java-приложениями выполняется в асинхронном режиме, т.е. процедура не ждет ответа от получателя. В качестве получателей сообщений, организующих очереди (queue), может быть либо программное обеспечение типа WebSphere MQ, связывающее приложения через канал обмена сообщениями, либо WEB-контейнер типа JBoss, GlassFish, обеспечивающих обмен сообщениями между приложениями контейнера, либо по каналам Интернета с использованием JNDI.

Получение сообщений java-приложением осуществляется либо по «подписке» (технология «издатель-подписчик»), либо из очереди («точка-точка»). Для получения сообщений по подписке необходимо должным образом подключиться к соответствующей очереди. При появлении в очереди сообщений они отправляются всем подписчикам. В модели «точка-точка» для получения сообщений необходимо периодически подключаться к соответствующей очереди и читать в ней сообщения.

В статье рассматриваются примеры отправки и получения сообщений с использованием как WEB-приложения (Java EE), так standalone приложения (Java SE). Описание примеров разделено на две части. На этой странице рассматривается взаимодействие WEB-приложения с провайдером HornetQ. Взаимодействие standalone Java приложения с Websphere MQ рассматривается здесь.

Пример обмена сообщения с сервером JBoss

В первом простейшем WEB-приложении «jms-jboss» для отправки и получения JMS сообщений в качестве контейнера будет использован сервер приложений Wildfly версии 8.2 (ранее JBoss Application Server или JBoss AS).

Настройка сервера приложений Wildfly

Чтобы использовать Wildfly для обмена сообщениями JMS необходимо настроить его файл конфигурации /standalone/configuration/standalone.xml. По умолчанию настройки JMS не включены в конфигурационный файл и их нужно определить вручную. Но можно использовать файл конфигурации standalone-full.xml, в котором сервер включает настройки JMS провайдера HornetQ, обеспечивающего создание соответствующих очередей и обмен сообщениями.

Для примера достаточно было добавить один элемент ‘ ‘, который работает внутри контейнера. Второй элемент «java:jboss/exported/jms/queue/test» может работать за пределами контейнера, т.е. из другой JVM. Для него обязательным условием является определение в начале наименования «java:jboss/exported/». Можно было бы конечно использовать и существующие очереди (ExpiryQueue и DLQ).

Примечание :
DLQ (Dead Letter Queue) – это локальная очередь, называемая инача как очередь недоставленных сообщений. Такую очередь создают для каждого менеджера очередей, чтобы отлавливать неотправленные сообщения, связанные с проблемами в сети или у получателя.

Если не создать DLQ, то ошибки в приложениях могут отключать каналы. В этом случае не только прекратится получение сообщений в очереди, но может нарушиться работа и провайдера MQ, к примеру, не будут получены и выполнены команды администратора. Рекомендуется проектировать приложения таким образом, чтобы избегать подобных сценариев. Кроме того, следует проводить мониторинг DLQ, поскольку поступающие в эту очередь сообщения чаще всего содержат ошибки.

Чтобы стартовать Wildfly с файлом конфигурации standalone-full.xml из IDE Eclipse необходимо открыть окно ‘JBoss Runtime’ и определить значение ‘Configuration file’. Для этого откройте вкладку Servers (Perspective ‘Java EE’) и дважды щелкните мышью на сервере Wildfly. В открывшемся окне Overview нажмите на ссылку ‘Runtime Enviroment’, в результате чего будет открыто окно ‘JBoss Runtime’ :

jms api что такое. Смотреть фото jms api что такое. Смотреть картинку jms api что такое. Картинка про jms api что такое. Фото jms api что такое

В конце страницы приведен Log сервера Wildfly, в котором показано создание соответствующих очередей и подключение MDB-объекта приложения к адаптеру HornetQ для получения JMS сообщений по подписке.

Описание примера

На следующем скриншоте приведена структура WEB-приложения jms-jboss, включающего :

Проект в среде IDE Eclipse с использованием maven представлен на следующем скриншоте.

jms api что такое. Смотреть фото jms api что такое. Смотреть картинку jms api что такое. Картинка про jms api что такое. Фото jms api что такое

Листинг сервлета ServiceServlet

Сервлет ServiceServlet вызывается со страницы index.jsp из браузера с использованием jQuery. В качестве параметров сервлет получает ‘prefix’ сообщения и команду ‘mode’. Для отправки JMS сообщения сервлет использует метод sendMessage класса Sender. Отправленные сообщения сервер Wildfly сразу же возвращает подписчику Receiver. Полученные сообщения сервлет читает из статической коллекции Receiver.messages, после чего очищает её.

Отправленные и полученные сообщения сервлет оформляет в виде HTML-кода и возвращает в браузер.

Листинг дескриптора приложения, web.xml

В дескрипторе приложения web.xml описывается сервлет ServiceServlet и его URL (url-pattern) для вызова, а также открываемая по умолчанию страница приложения.

Листинг класса отправителя сообщений Sender

Класс отправителя создается и «живет» вместе с WEB-приложением согласно аннотации @ApplicationScoped. При инсталляции сразу же определяются context и очередь queue. Сервлет отправляет текстовые сообщения, вызывая метод sendMessage.

Листинг получателя сообщений Receiver

Здесь следует несколько слов сказать о MDB (Message Driven Beans). Объект MDB используется для поддержки асинхронных коммуникаций в приложении, как правило, в сочетании с очередями. Клиент посылает сообщение в очередь, а MDB объект получает эти сообщения из очереди по подписке. Клиент не может вызывать MDB напрямую, связь обеспечивается с помощью сообщений JMS. MDB никогда не отвечает клиенту.

Класс получателя сообщений оформлен как MDB объект с использованием аннотации, в которой определен ряд параметров, включающий JNDI очереди ‘jms/queue/test’. Получатель реализует интерфейс javax.jms.MessageListener, согласно которому переопределяет метод onMessage.

При появлении в очереди ‘jms/queue/test’ сообщения сервер приложений Wildfly сразу же вызовет метод onMessage данного MDB-объекта и передаст ему в качестве параметра сообщение javax.jms.Message, текст которого будет сохранен в коллекции messages. Сервлет имеет прямой доступ к набору полученных сообщений messages с модификаторами public и static.

Листинг страницы index.jsp

На странице index.jsp определена библиотека jquery-3.2.1.min.js и JavaScript методы, которые используются для ajax-вызова сервлета. Интерфейс страницы включает текстовое поле ‘prefix’ и кнопки ‘Отправить’ и ‘Получить’.

Интерфейс страницы в браузере представлен на следующем скриншоте.

При нажатии на кнопку ‘Отправить’ вызывается JavaScript процедура sendMessages, определяющая значения параметров (mode, prefix) и вызывающая сервлет для отправки сообщений. Результат выполнения команды в виде набора сообщений, оформленных в HTML-коде, возвращается в функцию success, которая выкладывает его в поле sendJMS на странице. Если префикс не определен, то сервлет будет использовать по умолчанию значение ‘prefix’. Как только сообщения попадут в очередь сервер вернет их объекту ‘Receiver’ по подписке.

При нажатии на кнопку ‘Получить’ вызывается JavaScript процедура receiveMessages, определяющая значение параметры mode и вызывающая сервлет для чтения полученных по подписке сообщений. Результат выполнения команды в виде набора сообщений, оформленных в HTML-коде, возвращается в функцию success, которая выкладывает его в поле receiveJMS на странице.

jms api что такое. Смотреть фото jms api что такое. Смотреть картинку jms api что такое. Картинка про jms api что такое. Фото jms api что такое

Старт сервера Wildfly

Сервер приложений Wildfly «логирует» всю информацию. При старте из IDE Eclipse эта информация дополнительно выводится в консоль. Ниже представлена информация (в сокращенном виде), связанная с настройкой сервером JMS очередей и стартом приложения «jms-jboss». В предпоследней строке отображено подключение MDB (Message Driven Bean) ‘Receiver’ к провайдеру HornetQ.

Скачать пример

Исходный код рассмотренного примера в виде проекта Eclipse с использованием Maven можно скачать здесь (994 Кб).

Примеры взаимодействия Java приложения c Websphere MQ по отправки и чтению JMS сообщений представлены здесь.

Источник

Jms api что такое

[an error occurred while processing this directive]

Введение в JMS

[an error occurred while processing this directive](none)

Предисловие

Данная статья предназначена, как это следует из названия, для первичного ознакомления с одной из ключевых технологий J2EE, Java Message Service (JMS).

К сожалению, устоявшейся русской терминологии J2EE не существует. Да и та неустоявшаяся, что существует, далека от идеала. Мне, например, очень не нравится, когда Session Beanназывают Сессионным Бином. Ну уж если он «Сессионный», то почему «Бин», а не «Зерно»?

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

Статья нисколько не претендует на полноту освещения темы – для этого существует достаточно большое количество литературы, в том числе и доступной online.

Недостатки традиционных распределенных систем

Традиционные распределенные системы, построенные на основе RMI, обладают рядом существенных недостатков. Назовем основные:

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

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

Невозможно перенести серверное приложение с одного хоста на другой в runtime.

Лучше дела обстоят с CORBA. Используя CORBA Event Service или его расширение CORBA Notification Service, вы можете осуществлять эффективное асинхронное взаимодействие внутри системы. Но есть одно «НО». Производители CORBA middleware, в том числе и два лидера (Borland и Iona), предоставляют лишь рудиментарный Event Service. Полноценный Event и Notification Services необходимо приобретать у third-party производителей. Например, великолепный продукт OpenFusion от Prism Technologies, в котором реализованы все CORBA-сервисы (за мой достаточно большой практический опыт разработки CORBA-систем мне доводилось работать лишь с четырьмя из них: Naming, Trading, Event, Notification). К тому же CORBA достаточна сложна и требует очень высокой квалификации разработчиков. Достаточно сказать, что с точки зрения CORBA-специалиста EJB является всего лишь Java-имплементацией CORBA Object Framework в спецификации CORBA 3 (к сожалению, еще не реализованной ни одним производителем).

Message-Oriented Middleware (MOM)

Выходом из данной ситуации может служить Messaging System. Существует множество определений этого термина. Например, следующий: Messaging System– это распределенная система, основанная на асинхронном обмене сообщениями(messages) между компонентами системы.

Message-Oriented Middleware – это, грубо говоря, тот продукт, на основе которого и строится Messaging System. Примером может служить IBM MQSeries.

В отличие от традиционных систем, в Messaging Systemприложения общаются не напрямую, а посредством MOM. Если один компонент системы хочет послать сообщение другому компоненту, он посылает данное сообщение MOM, а уж MOM затем пересылает его адресату.

jms api что такое. Смотреть фото jms api что такое. Смотреть картинку jms api что такое. Картинка про jms api что такое. Фото jms api что такое

MOM позволяет избавиться от перечисленных в п.2 недостатков.

Приложение, пославшее сообщение, не должно ждать ответа, и может продолжать свою текущую деятельность.

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

Компоненты системы не связаны напрямую друг с другом (decoupled), а потому возможно перенесение компонентов с одного хоста на другой в runtime без ущерба для работоспособности системы.

Модели обмена сообщениями

Существует две «основных» модели обмена сообщениями:

Point-to-point модель применяется, когда одному или нескольким компонентам (так называемые senders) необходимо посать сообщение одному компоненту-адресату (receiver).

Модель основана на понятии message queue. Sendersпосылают сообщения в queue, а Receiver читает сообщения из queue.

jms api что такое. Смотреть фото jms api что такое. Смотреть картинку jms api что такое. Картинка про jms api что такое. Фото jms api что такое

Часто говорят, что в point-to-point модели есть один и только один receiver. Однако это не совсем верно. Может существовать несколько receivers, присоединенных к одной и той же queue. Но MOMдоставит сообщение только одному из них. Какому именно – зависит от реализации. Некоторые MOM доставляют сообщение первому зарегистрированному receiver, в то время как существуют реализации, осуществляющие round-robin.

Publish-subscribe модель применима, когда одному или нескольким компонентам (publishers) необходимо послать сообщение одному или нескольким компонентам-адресатам (subscribers). Данная модель основана на понятии message topic.

Publishers посылают сообщения в topic, и все subscribersданного topic получают эти сообщения.

jms api что такое. Смотреть фото jms api что такое. Смотреть картинку jms api что такое. Картинка про jms api что такое. Фото jms api что такое

Какую именно модель использовать – это зависит от того, какой вы видите вашу систему во-первых, и какой MOM-продукт вы используете во-вторых. Не все реализации поддерживают обе модели.

Pub-sub модель кажется более элегантной, и у разработчика может возникнуть желание строить все Messaging Systems на основе этой модели. Но следует знать, что многие pub-subсистемы не гарантируют доставку сообщений в том порядке, в каком они были посланы (в отличие от point-to-point, где queueреализует принцип first-in/first-out). Задача сохранения порядка следования сообщений не тривиальна даже в случае одного topic. А уж если необходимо сохранение порядка доставки сообщений в случае множественных topics – то сложность возрастает экспоненциально. Поэтому в случае pub-sub модели следует по возможности избегать ситуаций, когда порядок следования сообщений важен (либо используя заголовки и раздел свойств сообщений для синхронизации – об этом будет сказано ниже).

Java Message Service (JMS)

Java Message Service (JMS) – это Java API (то есть набор интерфейсов и классов) для работы с Message-Oriented Middleware. Данный набор определен в пакете javax.jms в дереве пакетов J2EE.

JMS реализован во множестве MOM-продуктов, среди которых наиболее известны iPlanet Message Queue, IBM MQSeries, Progress Software SonicMQ, Bea WebLogic Server, и, конечно, мой любимый Prism Technologies OpenFusion, который к тому же позволяет интегрировать J2EE и CORBA. Существуют и freeware имплементации.

JMS поддерживает обе «основных» модели обмена сообщениями. Однако спецификация не требует от производителя реализовывать обе модели. Впрочем, большинство JMS-продуктов на рынке реализуют как point-to-point, так и pub-sub.

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

Далее мы рассмотрим использование «основных» моделей в случае JMS, но прежде следует ввести определенную в спецификации терминологию.

ConnectionFactory – это, как нетрудно догадаться из названия, обьект, ответственный за создание JMS Connection. Администратор МОМ создает данный обьект и связывает его с деревом JNDI, так что клиент JMS может получить доступ к ConnectionFactory используя стандартный JNDI lookup-механизм. В случае point-to-point модели используется javax.jms.QueueConnectionFactory, в случае pub-sub модели – javax.jms.TopicConnectionFactory.

Connection – абстрактное представление реального соединения между клиентом JMS и MOM. В случае point-to-point модели используется javax.jms.QueueConnection, в случае pub-sub модели – javax.jms.TopicConnection.

Session – обьект, создаваемый JMS Connection и используемый клиентами для посылки и принятия сообщений. В случае point-to-point используется javax.jms.QueueSession, в случае pub-sub – javax.jms.TopicSession. Фактически, это главная «рабочая лошадка» JMS.

Destination – это либо queue, либо topic – в зависимости от используемой модели: javax.jms.Queue или javax.jms.Topic. Как и ConnectionFactory, destination связывается с деревом JNDI.

MessageProducer – обьект, который, собственно, и посылает сообщения. В случае point-to-point модели это javax.jms.QueueSender, в случае pub-sub – javax.jms.TopicPublisher.

MessageConsumer – обьект, принимающий сообщения. В случае point-to-point модели это javax.jms.QueueReceiver, в случае pub-sub – javax.jms.TopicSubscriber.

Message– сообщение. О типах сообщений будет сказано ниже.

Итак, приступим к созданию простейших sender и receiver.

// Используем JMS и JNDI пакеты
import javax.jms.*;
import javax.naming.*;
public class SimpleSender <
public static void main(String args[]) <
try <

//Сначала найдем сервис JNDI
Contect ctx = new InitialContext();
//Теперь найдем ConnectionFactory с помощью JNDI
//Имя, с которым зарегистрирован
// стандартный ConnectionFactory в дереве
// JNDIзависит от реализации –
// например, в случае WebLogic Server это
// weblogic.jms.ConnectionFactory
QueueConnectionFactory qcf =
(QueueConnectionFactory)ctx.lookup(
«MyConnectionFactory»);

//А теперь создадим Connection
QueueConnection con = qcf.createQueueConnection();
//Создадим Session со следующими свойствами:
//а)посылка сообщений не является частью транзакции
//б)подтверждение о получении сообщения осуществляет JMS
//автоматически
QueueSession session =
con.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);

//Найдем Destination с помощью JNDI. Если еще не существует
// (не зарегистрирована в JNDI) – создадим и зарегистрируем
Queue queue = null;
try <
queue = (Queue)ctx.lookup(«MyQueue»);
>catch(NameNotFoundException nnfe) <
queue = session.createQueue(«MyQueue»);
ctx.bind(«MyQueue»,queue);
>

//Простейшее текстовое сообщение
TextMessage textMessage =
session.createTextMessage();

//Создадим Producer
QueueSender sender =
session.createSender(queue);

//Активизируем Connection
con.start();
//Теперь мы готовы посылать сообщения
//Будем посылать наше сообщение каждую секунду
//или тот интервал, который указан в первом аргументе
long sendInterval;
try <
sendInterval = Long.parseLong(args[0]);
>catch(Exception rae) <
sendInterval = 1000;
>

//Пошлем, например, тысячу сообщений
for(int i=0;i

Sender создан. Приступим к созданию receiver.

Существует два пути получения сообщений. Первый – синхронное затребование сообщений из queue, используя метод receive() интерфейса javax.jms.QueueReceiver. Второй – асинхронное получение сообщений как только они становятся доступны – используя интерфейс javax.jms.MessageListener.

Многие шаги в создании receiverаналогичны таковым для sender – эту часть оставим без комментариев.

Первый пример receiver – с использованием receive().

import javax.jms.*;
import javax.naming.*;
public class SyncReceiver <
public static void main(String[] args) <
try <
Context ctx = new InitialContext();
QueueConnectionFactory qcf =
(QueueConnectionFactory)ctx.lookup(«MyConnectionFactory»);
QueueConnection con = qcf.createQueueConnection();
QueueSession session =
con.createQueueSession(false,Session.AUTO_ACKNOWLEDGE);
Queue queue = null;
try <
queue = (Queue)ctx.lookup(«MyQueue»);
>catch(NameNotFoundException nnfe) <
queue = session.createQueue(«MyQueue»);
ctx.bind(«MyQueue», queue);
>

// Создадим Consumer
QueueReceiver receiver = session.createReceiver(queue);
// Активизируем Connection
con.start();
//Мы готовы принимать сообщения
for(;;)<
//Обратите внимание на использование метода receive()
TextMessage textMessage = (TextMessage)receiver.receive();
System.out.println(«Got a message :»+textMessage.getText());
>
>catch(Exception e) <
e.printStackTrace();
>
>
>

Следующий пример – асинхронное получение сообщений с использованием интерфейса MessageListener.

Как видно из примеров, JMS API достаточно прост. В следующем разделе будет представлена pub-sub модель. Изменив point-to-point код всего в нескольких местах, Вы получите работающее pub-sub приложение.

Использование Pub-Sub модели в JMS

import javax.jms.*;
import javax.naming.*;

public class SimplePublisher <
public static void main(String[] args) <
try <
Context ctx = new InitialContext();

//Найдем ConnectionFactory
//В случае pub-sub это TopicConnectionFactory
TopicConnectionFactory tcf =
(TopicConnectionFactory)ctx.lookup(«MyTopicFactory»);

//Создадим TopicConnection
TopicConnection con = tcf.createTopicConnection();
//И затем TopicSession
TopicSession session =
con.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);

//Найдем topic в дереве JNDI
//или создадим новый
Topic topic = null;
try <
topic = (Topic)ctx.lookup(«MyTopic»);
>catch(NameNotFoundException nnfe) <
topic = session.createTopic(«MyTopic»);
ctx.bind(«MyTopic»,topic);
>
TextMessage textMessage = session.createTextMessage();

//Producer, в данном случае TopicPublisher
TopicPublisher publisher = session.createPublisher(topic);
con.start();
long sendInterval;
try <
sendInterval = Long.parseLong(args[0]);
>catch(Exception rae) <
sendInterval = 1000;
>
for(int i=0;i

Как видите, изменения в коде незначительны.

Как и в случае point-to-point, существует два способа получения сообщения: синхронный, с использованием метода receive() интерфейса TopicSubscriber, либо асинхронный, с использованием интерфейса MessageListener.

Приведу лишь список необходимых изменений в обоих случаях. Итак, в синхронном варианте, получив (либо создав) Topic, создайте consumer:

TopicSubscriber subscriber = session.createSubscriber(topic);

После активизации connection, вы можете получать сообщения:

TextMessage textMessage = (TextMessage)subscriber.receive();

В случае асинхронного получения сообщений, как и прежде, реализуйте метод onMessage интерфейса MessageListener, и зарегистрируйте новый Listener с помощью метода setMessageListener интерфейса TopicSubscriber.

Запустив несколько subscribers, вы увидите, что все они получают сообщения, посланные publishers.

Говоря о pub-sub модели, важно отметить следующее. В отличие от point-to-point случая, где сообщение, посланное в queue, остается там до тех пор, пока receiver не получит это сообщение, pub-sub по умолчанию такой возможностью (durability) не обладает. Иными словами, сообщения, посланные в topic будут доставлены только тем subscribers, которые активны – то есть доступны на данный момент.

Но не отчаивайтесь! Выход, конечно же есть! Все, что вам нужно сделать – создать durable subscriber:

TopicSubscriber subscriber =
session.createDurableSubscriber(topic,»MySubscriberName»);

Второй аргумент метода – это уникальное имя данного subscriber.

Теперь можно быть уверенным, что сообщения, посланные в topic, данный subscriber получит, даже если он не активен в момент посылки сообщения – когда станет активным.

Типы сообщений

В JMX определены следующие стандартные типы сообщений:

StreamMessage – сообщение, содержащее сериализованный поток обьектов

MapMessage – сообщение, содержащее пары «ключ-значение»

TextMessage – сообщение, содержащее строку

ObjectMessage– сообщение, содержащее сериализованный обьект

ByteMessage – сообщение, содержащее поток байтов

Кроме того, некоторые имплементации (например, OpenFusion и WebLogic) предоставляют еще один «почти стандартный» тип:

XMLMessage – расширение TextMessage, используется для доставки XMLсообщений

Все типы сообщений являются подклассами javax.jms.Message.

Заголовки и разделы свойств сообщений

Сообщения соостоят из трех частей: заголовка сообщения, раздела свойств и собственно тела сообщения.

Заголовок сообщения содержит дополнительную информацию, которую разработчик может использовать в своем приложении. JMS предоставляет get и set методы для каждого поля заголовка. Некоторые из них устанавливаютя автоматически, другие могут быть использованы разработчиком приложения.

JMSDestination – содержит имя destination, в который посылается сообщение.

JMSDeliveryMode – определяет, является ли сообщение сохраняемым или нет. Если оно сохраняемо, то будет сохранено MOM в базе данных (или в файле), а потому оно переживет «гибель» системы, в отличие от несохраняемого сообщения.

JMSExpiration – определяет, когда сообщение устареет и будет удалено из системы. По умолчанию сообщение не устаревает никогда.

JMSPriority – как и следует из названия, определяет приоритет сообщения (от 0 до 9). По умолчанию равно 4.

JMSMessageID – уникальный идентификатор сообщения

JMSTimestamp – содержит информацию, когда именно MOM приняла сообщение от producer.

JMSCorrelationID – может быть использовано разработчиком для согласования сообщений: например, если вы хотите переслать ряд сообщений, обьединенных в одну логическую группу (такую как набор товаров в заказе, при этом в каждое сообщение о товаре вы можете добавить в данное поле заголовка номер заказа).

JMSReplyTo – может быть использовано разработчиком для того, чтобы consumer знал, кому (то есть в какой destination) при желании отсылать ответ.

JMSType – поле может быть использовано разработчиком для того, чтобы дать приложению информацию, как обращаться с данным сообщением. Тип здесь понимается как application-specific type, а не тот, что использован выше в разделе «типы сообщений».

JMSRedelivered – устанавливается, если сообщение не было доставлено с первой попытки – например, в случае, когда consumer не подтвердил получение сообщения (если он должен был подтвердить, конечно)

Раздел свойств содержит пары «ключ-значение», которые могут быть использованы для пересылки определенных данных между producer и consumer. В качестве значений могут быть использованы примитивные типы (boolean, byte, float, double, short, int, long), а так же строки (java.lang.String).

Устанавливаются и читаются они с помощью соответствующих set и getметодов. Например, для установки integer-свойства с ключом «MyProperty» и значением равным 100:

int value = textMessage.getIntProperty(«MyProperty»);

Доставка сообщений

Сообщение может быть сохраняемым или несохраняемым. Если сообщение сохраняемо, то MOM сохранит его в базе данных или файле. Такое сообщение переживет «гибель» MOM. Какой тип сообщения выбрать – зависит от того, что вы ожидаете от своей Messaging System: большей надежности (в случае сохраняемых сообщений), либо большей производительности (в случае несохраняемых).

Вы можете установить режим доставки сообщения в момент его посылки(по умолчанию режим будет таким, каким его установил администратор при создании ConnectionFactory). Например:

textMessage.setText(«It’s my message»);
sender.send(textMessage, DeliveryMode.NON_PERSISTENT,
messagePriority, messageTimeToLive);

Подтверждение получения сообщения

JMS поддерживает три «основных» модели подтверждения получения сообщения.

AUTO_ACKNOWLEDGE – в случае синхронного получения сообщений, подтверждение получения будет произведено автоматически, когда метод receive() возвратит значение не вызвав никакой исключительной ситуации. В случае асинхронного получения сообщений, подтверждение получения будет произведено, когда метод onMessage() вернет значение.

DUPS_OK_ACKNOWLEDGE – работа по подтверждению получения сообщения перекладывается на Session. Сообщения будут вновь доставлены в случае возникновения ошибки или «гибели» системы.

CLIENT_ACKNOWLEDGE – клиент должен вызвать метод acknowledge() интерфейса javax.jms.Message для того, чтобы явно подтвердить получение сообщения. При вызове данного метода будет подтверждено получение текущего и всех предидущих полученных сообщений.

Какой тип подтверждения сообщения выбрать – опять-таки решать вам на основе анализа требований к вашей системе.

AUTO_ACKNOWLEDGE – самый простой тип. Там где не требуется очень высокая производительность – этот тип вполне уместен.

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

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

Посылка сообщений как часть транзакции

Очень часто возникает необходимость посылать сообщения в контексте транзакции. Например, получив сообщение из queue 1, consumerпосылает это сообщение в другую queue 2. В этот момент происходит исключительная ситуация. И Вы, естественно, хотите, чтобы система вернулась в первоначальное состояние, то есть сообщение вновь оказалось в queue 1.

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

Первый подход заключается в использовании transacted sessions. Как этого добиться? Очень просто – поставить флаг transacted при создании Вашей session в значение true:

Session session = con.createQueueSession(
true,Session.AUTO_ACKNOWLEDGE);

Важно отменить, что в случае transacted session второй аргумент – тип подтверждения получения – хоть и присутствует, но игнорируется JMS. И подтверждение получения будет произведено, когда транзакция будет завершена методом commit() обьекта session, который должен быть вызван клиентом, получающим сообщение. Интерфейс javax.jms.Session включает два метода: commit() для подтверждения транзакции и rollback() для отката к первоначальному состоянию.

В данном случае используется chained transaction model. Что это означает? Только то, что в случае успешного завершения транзакции, JMSавтоматически создает новую транзакцию.

И producer, и consumer могут использовать transacted session.

Когда producer использует transacted session, посланные сообщения накапливаются в буфере до тех пор, пока producer не вызовет либо commit(), либо rollback(). В случае вызова commit(), сообщения будут доступны для доставки, в случае вызова rollback(), JMS»очистит» буфер.

В случае, когда consumer использует transacted session, этот sessionконтролирует подтверждение доставки сообщения. В случае вызова commit() производится подтверждение получения сообщений в контексте данной транзакции, в случае вызова rollback() JMS вернет все сообщения в соответствующий destination.

Второй подход заключается в использовании JTA-транзакций совместно с JMS. Этот подход позволяет разработчику включать в единую транзакцию как посылку сообщений, так и запрос к базе данных или EJB.

Достигается это стандартным способом – использованием javax.transaction.UserTransaction. Например,

UserTransaction myTransaction =
(UserTransaction)ctx.lookup(«MyUserTransaction»);
myTransaction.begin();
sender.send(textMessage);
myStatement.executeUpdate(
«INSERT INTO testTable VALUES (100,’BILL’)»);
myTransaction.commit();

При этом важно отметить, что JTA не может быть использован совместно с transacted session. Либо пироги, либо пряники. Если Вы попытаетесь совместить несовместимое, то увидите, что transacted session будет игнорировать вызовы commit() или rollback() интерфейса UserTransaction.

Как и в случае transacted session, тип подтверждения получения сообщения будет игнорироваться.

Когда будет вызван метод commit(), все посланные сообщения будут доступны для доставки. Будет произведено подтверждение для всех полученых сообщений.

Message-Driven Beans

Несколько слов о новом типе EJB в спецификации 2.0.

Новая спецификация EJB 2.0 (реализованная на данный момент только в Weblogic 6.x и, кажется, JBoss 2.x), вводит 3 революционных изменения по онтошению к EJB 1.1

В предыдущей спецификации, при необходимости интергрировать JMS и EJB приходилось идти на различные ухищрения (Weblogic 5.1 для облегчения страданий разработчиков даже предоставлял для этой цели Startup класс). Вызвано это тем, что доступ непосредственно к EJB имеет только контейнер, для клиента же единственный выход – remote interface.

Message Driven Bean (MDB) – это долгожданный плод любви EJB и JMS.

Главная отличительная черта MDB – это то, что клиент не общается с ним посредством remote interface (ни Object-, ни Home-интерфейса MDB не имеет). Единственный способ общения – посылка сообщений. MDB – это просто MessageListener, и ничего больше: класс реализует javax.ejb.MessageDrivenBean и javax.jms.MessageListener. Первый из этих интерфейсов имеет всего два метода:

setMessageDrivenContext и ejbRemove. Второй интерфейс вообще куцый – как Вы помните, он имеет лишь один метод onMessage. Спецификация требует также создания метода ejbCreate без параметров.

Раз клиент не общается непосредственно с MDB, то он его и не создает. Контейнер сам решит, когда и сколько ему требуется MDB для обработки сообщений из данного destination.

Главный недостаток MDB – он может принимать сообщения только из одного destination.

Заключение

В заключение приведу несколько ссылок на доступные в сети ресурсы по данной тематике.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *