Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Java JMS.docx
Скачиваний:
3
Добавлен:
01.05.2025
Размер:
1.02 Mб
Скачать

1.2 Сообщения

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

Сообщение в JMS - это Java-объект, состоящий из заголовка (header) и тела (body). В заголовке находится служебная информация, а тело сообщения содержит в себе пользователь­ские данные.

JMS API определяет несколько типов сообщений:

  • BytesMessage содержит массив примитивов в теле сообщения. Таким образом, может быть использован для передачи данных между двумя приложениями в их родном формате, который может быть несовместим с другими типами Message. Также, может быть полезным в тех случаях, когда JMS используется как транспорт между двумя системами. Поскольку в нем можно хранить примитивные типы данных, они могут быть неправильно интерпретированы. Например, long может быть сохранен как short. Это может вызывать ошибки. Поэтому реко­мендуется читать данные строго в одном порядке и использовать те же типы данных, которые были использованы отправителем. 

  • StreamMessage содержит поток java-примитивов в теле сообщения. Содержит нес­ко­лько удобных методов для чтения данных, сохраненных в сообщении. Однако, StreamMe­s­sa­ge предотвращает неправильную интерпретацию данных. Например, чтение long как short. Это достигается тем фактом, что StreamMessage записывает также информацию о типах дан­ных, а не только их значения. 

  • TextMessage содержит в виде сообщения объект java.lang.String. Таким образом, его полезно использовать для обмена текстовыми данными. Также, может быть использован для обмена комплексными текстовыми данными на подобии XML-документов. 

  • ObjectMessage содержит объекты, реализующие интерфейс Serializable. Тем самым, позволяя приложениям обмениваться друг с другом объектами Java. Получатель сообщения должен привести тип объекта сообщения к реальному типу объекта. Поэтому, перед получением объекта, получатель должен знать действительный тип отосланного объекта. Неправи­льное приведение типов может породить ClassCastException. Более того, определение класса объекта, отосланного в сообщении, должно быть доступно на обоих машинах. Если определение класса недоступно на получателе, будет порождено исключение ClassNotFound­Excep­tion. Некоторые типы MOM могут поддерживать динамическую загрузку необходимых клас­сов по сети, но спецификация JMS не определяет это как обязательный пункт. 

  • MapMessage содержит данные в формате ключ-значение. Таким образом, тело сооб­щения представляет из себя ни что иное, как объект java.util.Properties. Значениями ключей могут быть Java примитивы или их оболочки. 

Отметим также, что BytesMessage хранит данные примитивных типов посредством перевода их в байтовое представление. Таким образом, сообщение становится одни сплошным куском байтов. StreamMessage умеет различать типы данных, которые хранятся в теле сооб­щения, поскольку хранит информацию о типах данных. BytesMessage позволяет читать дан­ные с использованием любого типа. Это может вызвать ошибки при неправильном считывание различных типов данных. Например, long считывается в short

Структура сообщения

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

Заголовок сообщения содержит значения полей сообщения, которые разработчик может использовать в приложении (таблица 1).

Таблица 1

Поле

Описание

JMSDestination

Содержит имя расположения, в которое посылается сообщение

JMSDeliveryMode

Определяет, является ли сообщение сохраняемым или нет

JMSExpiration

Определяет, когда сообщение устареет и будет удалено из системы (по умолчанию сообщение не устаревает никогда)

JMSPriority

Определяет приоритет сообщения от 0 до 9 (по умолчанию 4)

JMSMessageID

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

JMSTimestamp

Содержит информацию, когда именно MOM приняла сообщение от поставщика

JMSCorrelationID

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

JMSReplyTo

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

JMSType

Может быть использован разработчиком для того, чтобы дать приложению информацию, как обращаться с данным сообщением; тип здесь понимается как application-specific type

JMSRedelivered

Устанавливается, если сообщение не было доставлено с первой попыт­ки, например, в случае, когда потребитель не подтвердил получение сообщения

JMS предоставляет методы get( ) и set( ) получения и установки значений для каждого поля заголовка.

Раздел свойств содержит пары «ключ - значение», которые могут быть использованы для пересылки определенных данных между поставщиком и потребителем. В качестве значений могут быть использованы примитивные Java-типы (boolean, byte, float, double, short, int, long), а также строки (java.lang.String). Свойства устанавливаются и читаются с помощью со­ответствующих методов set( ) и get( ). Например, для установки integer-свойства с ключом "MyProperty"  и значением равным 100 нужен код:

textMessage.setIntProperty("MyProperty", 100);

, а для чтения:

int value = textMessage.getIntProperty("MyProperty");

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

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

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

textMessage.setText("It's my message"); sender.send(textMessage, DeliveryMode.NON_PERSISTENT, messagePriority, messageTimeToLive);

Уведомления о доставке сообщений - это механизм, при котором провайдер оповеща­ется о том, было ли сообщение доставлено адресату. Тип уведомления обычно задается при создании объекта сессии. Всего типов уведомления три:

  • Session.DUPS_OK_ACKNOWLEDGE - «ленивое» уведомление о доставке. При нем сводится к минимуму работа по нахождению дубликатов сообщения. Должно использоваться только в том случае, если ожидается появление дублирующих сообщений.

  • Session.AUTO_ACKNOWLEDGE - автоматическое уведомление об отправке при получении сообщения адресатом.

  • Session.CLIENT_ACKNOWLEDGE - уведомление об отправке устанавливается вручную вызовом метода acknowledge( ) объектов Message.

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

Отсеивание сообщений

JMS предоставляет механизм под названием селектор сообщений (message selector), позволяющий приложению фильтровать и классифицировать принимаемые сообщения. Селектор сообщений — это строка, содержащая выражение, основанное на спецификации SQL92. Селектор вызывается каждый раз при получении очередного сообщения. Сообщения, прошедшие отбор по критерию, становятся доступными приложению, остальные отбрасыва­ются. Выборка основана на сравнении полей заголовка и свойств сообщения.

Транзакции

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

Рисунок 4 - Использование механизма транзакций в КИС

Если в процессе передачи данных в пределах транзакции возникла хоть одна ошибка, всю транзакцию можно откатить (rollback).

Например, получив сообщение из очереди queue1, потребитель посылает это сообщение в другую очередь queue2. Если в этот момент происходит исключительная ситуация, то желательно, чтобы КИС вернулась в первоначальное состояние, т.е. сообщение вновь оказалось в очереди queue1.

Одно из главных преимуществ JMS в том, что посылка сообщения может быть частью транзакции. За создание и контроль транзакций отвечает объект Session. Распределенные транзакции могут поддерживаться посредством использования Java Transaction API (JTA).

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

Первый подход заключается в использовании transacted sessions. Для этого достаточно при создании session выставить флаг transacted в значение true:

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

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

И поставщик, и потребитель могут использовать transacted session.

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

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

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

Достигается это стандартным способом – использованием javax.transaction.UserTran­sac­ti­on. Например:

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

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]