@Resource(lookup = "java:comp/DefaultJMSConnectionFactory")
private static ConnectionFactory connectionFactory;
Java Platform, Enterprise Edition (Java EE) 8 Учебник по Java EE |
Назад | Вперёд | Содержание |
Основные строительные блоки приложения JMS:
Администрируемые объекты: фабрики и направления связи
Соединения
Сессии
Объекты JMSContext
, объединяющие соединение и сессию в одном объекте
Производители сообщений
Потребители сообщений
Сообщения
Рисунок 48-5 показывает, как все эти объекты сочетаются друг с другом в клиентском приложении JMS.
JMS также предоставляет браузеры очереди — объекты, которые позволяют приложению просматривать сообщения в очереди.
В этом разделе кратко описаны все эти объекты и приведены примеры команд и фрагменты кода, которые показывают, как создавать и использовать объекты. В последнем подразделе кратко описывается обработка исключений JMS API.
Примеры, которые показывают, как объединить все эти объекты в приложениях, приведены в главе 49 «Примеры JMS», начинающейся с написания простых приложений JMS. Для получения дополнительной информации см. документацию JMS API, входящей в состав документации API Java EE.
Две части приложения JMS — пункты назначения и фабрики соединений — обычно обслуживаются административно, а не программно. Технология, лежащая в основе этих объектов, вероятно, будет сильно отличаться от одной реализации JMS API к другой. Следовательно, управление этими объектами относится к административным задачам, которые варьируются от поставщика к поставщику.
Клиенты JMS получают доступ к администрируемым объектам через переносимые интерфейсы, поэтому клиентское приложение может работать практически без изменений в нескольких реализациях JMS API. Обычно администратор настраивает администрируемые объекты в пространстве имён JNDI, а клиенты JMS затем получают к ним доступ с помощью инъецирования.
Используя GlassFish Server, вы можете использовать команду asadmin create-jms-resource
или Консоль администрирования для создания администрируемых объектов JMS в форме ресурсов коннектора. Вы также можете указать ресурсы в файле с именем glassfish-resources.xml
, который можно связать с приложением.
В среде IDE NetBeans имеется мастер, позволяющий создавать ресурсы JMS для сервера GlassFish. Подробности смотрите в Административное создание объектов JMS.
Спецификация платформы Java EE позволяет разработчику создавать администрируемые объекты с использованием аннотаций или элементов дескриптора развёртывания. Объекты, созданные таким образом, специфичны для приложения, для которого они созданы. Подробности смотрите в Создание ресурсов для приложений Java EE. Определения в дескрипторе развёртывания переопределяют указанные в аннотациях.
Фабрика соединений — это объект, который клиент использует для создания соединения с провайдером. Фабрика соединений содержит набор параметров конфигурации соединения, которые были определены администратором. Каждая фабрика соединений является объектом интерфейса ConnectionFactory
, QueueConnectionFactory
или TopicConnectionFactory
. Чтобы узнать, как создавать фабрики соединений, см. Административное создание объектов JMS.
В начале клиентской программы JMS инъецируйте ресурс фабрики соединений в объект ConnectionFactory
. Сервер Java EE должен предоставить фабрике соединений JMS логическое имя JNDI java:comp/DefaultJMSConnectionFactory
. Фактическое имя JNDI будет зависеть от реализации.
Например, следующий фрагмент кода ищет фабрику соединений JMS по умолчанию и назначает её объекту ConnectionFactory
:
@Resource(lookup = "java:comp/DefaultJMSConnectionFactory")
private static ConnectionFactory connectionFactory;
Пункт назначения — это объект, который клиент использует для указания цели отправляемых сообщений и источника получаемых сообщений. При обмене сообщениями типа "точка-точка" пункты назначения называются очередями. При обмене "публикация-подписка" — темами. Приложение JMS может использовать несколько очередей или тем (или и то и другое). Чтобы узнать, как создавать ресурсы пунктов назначения, см. Административное создание объектов JMS.
Чтобы создать пункт назначения с помощью сервера GlassFish, создайте ресурс пункта назначения JMS и укажите для него имя JNDI.
В реализации Jakarta Messaging сервера GlassFish каждый пункт назначения ссылается на физическое назначение. Физический пункт назначения может быть создан явным образом. Если это не сделано, сервер приложений создаст его, когда это необходимо, и удалит его вместе с соответствующим ресурсом.
Помимо инъецирования ресурса фабрики соединений в клиентскую программу, обычно инъецируется и пункт назначения. В отличие от фабрик соединений, пункты назначения отличаются для способов обмена сообщениями "точка-точка" и "публикация-подписка". Чтобы создать приложение, позволяющее использовать один и тот же код как для тем, так и для очередей, вы назначаете пункт назначения для объекта Destination
.
Следующий код указывает два ресурса: очередь и тему. Имена ресурсов отображаются на целевые ресурсы, созданные в пространстве имён JNDI:
@Resource(lookup = "jms/MyQueue")
private static Queue queue;
@Resource(lookup = "jms/MyTopic")
private static Topic topic;
В приложении Java EE администрируемые объекты JMS обычно помещаются в субконтекст именования jms
.
С помощью общих интерфейсов вы можете смешивать или сопоставлять фабрики соединений и пункты назначения. То есть, в дополнение к использованию интерфейса ConnectionFactory
, вы можете инъецировать ресурс QueueConnectionFactory
и использовать его с Topic
, а также можете добавить TopicConnectionFactory
и использовать его с Queue
. Поведение приложения будет зависеть от типа используемого пункта назначения, а не от типа используемой фабрики соединений.
Соединение инкапсулирует виртуальное соединение с провайдером JMS. Например, соединение может представлять собой открытый сокет TCP/IP между клиентом и демоном службы провайдера. Соединение используется для создания одной или нескольких сессий.
Замечание: В платформе Java EE возможность создания нескольких сессий из одного подключения ограничена клиентскими приложениями. В веб-компонентах и компонентах Enterprise-бина соединение может создавать не более одной сессии. |
Обычно соедиинение создаётся при создании объекта JMSContext
. Смотрите Объекты JMSContext для подробностей.
Сессия — это однопоточный контекст для отправки и получения сообщений.
Обычно сессия (а также соединение) создаётся вместе с созданием объекта JMSContext
. Смотрите Объекты JMSContext для подробностей. Сессии используются для создания производителей сообщений, потребителей сообщений, собственно сообщений, браузеров очередей и вре́менных пунктов назначения.
Сессии сериализуют выполнение слушателей сообщений. Подробности см. в разделе Слушатели сообщений JMS.
Сессия обеспечивает транзакционный контекст, с помощью которого можно сгруппировать набор отправлений и приёмов сообщений в атомарную операцию. Подробнее см. Использование локальных транзакций JMS.
Объект JMSContext
содержит в себе соединение и сессию. То есть он обеспечивает как активное соединение с провайдером JMS, так и однопоточный контекст для отправки и получения сообщений.
JMSContext
используется для создания следующих объектов:
Производители сообщений
Потребители сообщений
Сообщения
Браузеры очереди
Вре́менные очереди и темы (см. Создание вре́менных пунктов назначения)
Можно создать JMSContext
в блоке try
-with-resources.
Чтобы создать JMSContext
, вызовите метод createContext
фабрики соединений:
JMSContext context = connectionFactory.createContext();
При вызове без аргументов из клиентского приложения или клиента Java SE или из веб-контейнера Java EE или контейнера EJB, когда не выполняется активная транзакция JTA, метод createContext
создаёт нетранзакционную сессию с режимом подтверждения JMSContext.AUTO_ACKNOWLEDGE
. При вызове без аргументов из веб-контейнера или контейнера EJB, когда выполняется активная транзакция JTA, метод createContext
создаёт транзакционную сессию. Для получения информации о том, как транзакции JMS работают в приложениях Java EE, см. Использование JMS API в приложениях Java EE.
Чтобы создать транзакционную сессию в клиентском приложении или клиенте Java SE, также можно вызвать метод createContext
с аргументом JMSContext.SESSION_TRANSACTED
:
JMSContext context =
connectionFactory.createContext(JMSContext.SESSION_TRANSACTED);
Сессия использует локальные транзакции. Подробнее смотрите Использование локальных транзакций JMS.
Кроме того, можно указать режим подтверждения не по умолчанию. Смотрите Управление подтверждением сообщения для получения дополнительной информации.
При использовании JMSContext
доставка сообщений начинается при создании потребителя. Смотрите Потребители сообщений JMS для получения дополнительной информации.
Если JMSContext
создаётся в блоке try
-with-resources, не требуется закрывать его явно. Он будет закрыт, когда закончится блок try
. Убедитесь, что приложение выполняет все действия JMS в блоке try
-with-resources. Если блок try
-with-resources не используется, нужно вызвать метод close
в JMSContext
, чтобы закрыть соединение, когда приложение закончит свою работу.
Источник сообщений — это объект, который создаётся JMSContext
-ом или сессией и используется для отправки сообщений в пункт назначения. Источник сообщений, созданный JMSContext
, реализует интерфейс JMSProducer
. Вы можете создать его следующим образом:
try (JMSContext context = connectionFactory.createContext();) {
JMSProducer producer = context.createProducer();
...
Однако JMSProducer
— это легковесный объект, который не потребляет значительных ресурсов. По этой причине не нужно сохранять JMSProducer
в переменной. Его можно создавать новый каждый раз, когда возникает необходимость отправить сообщение. Отправляйте сообщения в определённый пункт назначения с помощью метода send
. Например:
context.createProducer().send(dest, message);
Вы можете создать сообщение в переменной перед отправкой, как показано здесь, или создать его с помощью вызова send
. Дополнительная информация приведена в разделе Сообщения JMS .
Потребитель сообщений — это объект, который создаётся с помощью JMSContext
или сессией и используется для получения сообщений, отправленных в пункт назначения. Источник сообщений, созданный JMSContext
, реализует интерфейс JMSConsumer
. Самый простой способ создать получателя сообщения — использовать метод JMSContext.createConsumer
:
try (JMSContext context = connectionFactory.createContext();) {
JMSConsumer consumer = context.createConsumer(dest);
...
Потребитель сообщений позволяет клиенту JMS регистрироваться в пункте назначения у провайдера JMS. Провайдер JMS управляет доставкой сообщений из пункта назначения зарегистрированным в этом пункте пользователям.
Когда для создания получателя сообщения используется JMSContext
, доставка сообщения начинается сразу после его создания. Это поведение может быть отключено вызовом setAutoStart(false)
при создании JMSContext
, а затем явным вызовом метода start
для начала доставки сообщений. Если нужно временно остановить доставку сообщений без закрытия соединения, можно вызвать метод stop
. Для возобновления доставки сообщений вызовите start
.
Метод receive
используется для синхронного получения сообщения. Этот метод может быть использован в любое время после создания потребителя.
Если не указать аргументов или указать аргумент 0
, метод блокируется на неопределённый срок до прибытия сообщения:
Message m = consumer.receive();
Message m = consumer.receive(0);
Для простого клиента это может не иметь значения. Но если возможно, что сообщение может быть недоступно, используйте синхронный приём с тайм-аутом: вызовите метод receive
с аргументом тайм-аута, большим, чем 0
. Одна секунда является рекомендуемым значением времени ожидания:
Message m = consumer.receive(1000); // тайм-аут 1 секунда
Чтобы включить асинхронную доставку сообщений от клиентского приложения или клиента Java SE, используйте слушатель сообщений, как описано в следующем разделе.
Для создания долговременной подписки на темы может использоваться метод JMSContext.createDurableConsumer
. Этот метод применим только к темам. Для получения дополнительной информации см. Создание долговременных подписок. Для тем также могут создаваться общие потребители. См. Создание общих подписок.
Слушатель сообщений — это объект, который действует как асинхронный обработчик событий для сообщений. Этот объект реализует интерфейс MessageListener
, содержащий метод onMessage
. В методе onMessage
определяются действия, которые должны быть выполнены при получении сообщения.
Используя метод setMessageListener
, в клиентском приложении или клиенте Java SE регистрируется слушатель сообщений с определённым потребителем сообщений. Например, класс с именем Listener
, реализующий интерфейс MessageListener
, может быть зарегистрирован как слушатель сообщений следующим образом:
Listener myListener = new Listener();
consumer.setMessageListener(myListener);
Когда начинается доставка сообщения, провайдер JMS автоматически вызывает метод слушателя сообщения onMessage
при каждой доставке сообщения. Метод onMessage
принимает один аргумент типа Message
, который ваша реализация метода может при необходимости привести к другому подтипу сообщения (см. Тело сообщения) ,
В веб-контейнере Java EE или контейнере EJB управляемые сообщениями компоненты используются для асинхронной доставки сообщений. Управляемый сообщениями компонент также реализует интерфейс MessageListener
и содержит метод onMessage
. Для получения дополнительной информации см. Использование управляемых сообщениями бинов для асинхронного получения сообщений.
Ваш метод onMessage
должен обрабатывать все исключения. Выбрасывание RuntimeException
считается ошибкой программирования.
Простой пример использования слушателя сообщений см. в разделе Использование слушателя сообщений для асинхронной доставки сообщений. Глава 49 «Примеры JMS», содержит ещё несколько примеров слушателей сообщений и управляемых сообщениями бинов.
Если приложению для обмена сообщениями необходимо фильтровать полученные сообщения, может использоваться селектор сообщений JMS, позволяющий получателю сообщений указать интересующий его пункт назначения. Селекторы сообщений передают работу по фильтрации сообщений провайдеру JMS, а не приложению. Приложение, использующее селектор сообщений, см. в разделе Отправка сообщений из сессионного компонента в MDB.
Селектор сообщений — выражение типа String
. Синтаксис этого выражения основан на подмножестве синтаксиса условного выражения SQL92. Селектор сообщений в этом примере выбирает любое сообщение со свойством NewsType
, для которого установлено значение 'Sports'
или 'Opinion'
:
NewsType = 'Sports' OR NewsType = 'Opinion'
Методы createConsumer
и createDurableConsumer
, а также методы для создания общих потребителей позволяют указывать селектор сообщений в качестве аргумента при создании получателя сообщения.
Получатель сообщений получает только те сообщения, заголовки и свойства которых соответствуют селектору. (См. Заголовки сообщений и Свойства сообщения.) Селектор сообщений не может выбирать сообщения на основе содержимого тела сообщения.
Семантика получения сообщений из тем более сложна, чем из очередей.
Приложение получает сообщения из темы, создавая подписку на эту тему и получателя на эту подписку. Подписки могут быть или не быть долговременными (durable), быть или не быть общими (shared).
Подписка может рассматриваться как объект внутри самого провайдера JMS, тогда как потребитель является объектом JMS в приложении.
Подписка будет получать копию каждого сообщения, отправляемого в тему после создания подписки, если не указан селектор сообщений. Если селектор сообщений указан, в подписку будут добавлены только те сообщения, свойства которых соответствуют селектору сообщений.
Подписки, не являющиеся общими, ограничены одним потребителем. В этом случае все сообщения в подписке доставляются этому потребителю. Общие подписки позволяют доставку нескольким потребителям. В этом случае каждое сообщение в подписке доставляется только одному потребителю. JMS не определяет, как сообщения распределяются между несколькими пользователями по одной и той же подписке.
Подписки могут быть или не быть долговременными.
Подписка, не являющаяся долговременной, существует только до тех пор, пока в ней есть активный потребитель. Это означает, что любые сообщения, отправленные в тему, будут добавлены в подписку, только если потребитель существует и не закрыт.
Подписка, не являющаяся долговременной, может быть как быть общей, так и не быть ею.
Подписки, не являющиеся долговременными и общими, не имеют имени и с ними может быть связан только один объект-потребитель. Они создаются автоматически при создании объекта-потребителя. Они не сохраняются и автоматически удаляются при закрытии объекта-потребителя.
Метод JMSContext.createConsumer
создаёт получателя для подписки, не являющейся долговременной общей, если в качестве пункта назначения указана тема.
Общая подписка, не являющаяся долговременной, идентифицируется по имени и необязательному идентификатору клиента и может иметь несколько объектов-потребителей, получающих от неё сообщения. Она создаётся автоматически при создании первого объекта-потребителя. Она не сохраняется и удаляется автоматически при закрытии последнего объекта-потребителя. Смотрите Создание общих подписок для получения дополнительной информации.
За счёт более высоких накладных расходов подписка может быть долговременной. Долговременная подписка сохраняется и продолжает накапливать сообщения до тех пор, пока не будет явно удалена, даже если нет объектов-потребителей, получающих сообщения от неё. Подробности смотрите в Создание долговременных подписок.
Чтобы гарантировать, что приложение "публикация-подписка" получает все отправленные сообщения, используйте долговременные подписки для потребителей этой темы.
Как и подписка, не являющаяся долговременной, долговременная подписка может быть или не быть общей.
Долговременная подписка, не являющаяся общей, идентифицируется по имени и идентификатору клиента (который должен быть установлен) и может иметь только один объект-потребитель, связанный с ней.
Общая долговременная подписка идентифицируется по имени и необязательному идентификатору клиента и может иметь несколько объектов-потребителей, получающих от неё сообщения.
Долговременная подписка будет называться неактивной, если она существует, но с ней в настоящее время не связан ни один незакрытый потребитель.
Вы можете использовать метод JMSContext.createDurableConsumer
, чтобы создать получателя для долговременной подписки, не являющейся общей. У такой подписки одновременно может быть только один активный потребитель.
Потребитель идентифицирует долговременную подписку, из которой он получает сообщения, указав уникальный идентификатор, хранимый провайдером JMS. Последующие объекты-потребители, имеющие одинаковые идентификационные данные, возобновляют подписку в том состоянии, в котором она была оставлена предыдущим потребителем. Если у долговременной подписки нет активного потребителя, провайдер JMS сохраняет сообщения подписки до тех пор, пока они не будут получены подпиской или пока не истечёт срок их действия.
Уникальность долговременной подписки, не являющейся общей, достигается сочетанием следующих частей:
Идентификатор клиента для соединения
Тема и название подписки
Вы можете установить идентификатор клиента административно для конкретной фабрики соединений, используя либо командную строку, либо Консоль администрирования. (В клиентском приложении или клиенте Java SE вместо этого вы можете вызвать JMSContext.setClientID
.)
После использования этой фабрики соединений для создания JMSContext
вызывается метод createDurableConsumer
с двумя аргументами: темой и именем подписки:
String subName = "MySub";
JMSConsumer consumer = context.createDurableConsumer(myTopic, subName);
Подписка становится активной после создания потребителя. Позже потребитель может быть закрыт:
consumer.close();
Провайдер JMS хранит сообщения, отправленные в тему, так же, как и сообщения, отправленные в очередь. Если программа или другое приложение вызывает createDurableConsumer
с использованием той же фабрики соединений и её идентификатора клиента, той же темой и тем же именем подписки, тогда подписка повторно активируется, и провайдер JMS доставляет сообщения, отправленные за период неактивности подписки.
Для удаления долговременной подписки, сначала закройте получателя, затем вызовите метод unsubscribe
с именем подписки в качестве аргумента:
consumer.close();
context.unsubscribe(subName);
Метод unsubscribe
удаляет состояние, которое провайдер поддерживает для подписки.
Рисунок 48-6 и рисунок 48-7 показывают разницу между долговременной подпиской и подпиской, не являющейся долговременной. При обычной (не долговременной) подписке потребитель и подписка начинаются и заканчиваются в одной точке и фактически идентичны. Когда потребитель закрыт, подписка также заканчивается. Здесь create
обозначает вызов JMSContext.createConsumer
с аргументом Topic
, а close
обозначает вызов JMSConsumer.close
. Любые сообщения, отправленные в тему между временем первого close
и временем второго create
, не добавляются ни в одну подписку. На рисунке 48-6 потребители получают сообщения M1, M2, M5 и M6, но не получают M3 и M4.
При наличии долговременной подписки потребитель может быть закрыт и повторно создан, но подписка продолжает существовать и хранить сообщения до тех пор, пока приложение не вызовет метод unsubscribe
. На рис. 48-7 create
обозначает вызов JMSContext.createDurableConsumer
, close
обозначает вызов JMSConsumer.close
и unsubscribe
означает вызов JMSContext.unsubscribe
. Сообщения, отправленные после закрытия первого потребителя, принимаются при создании второго потребителя (по той же долговременной подписке), поэтому даже если сообщения M2, M4 и M5 поступают, когда нет потребителя, они не теряются.
Общая долговременная подписка позволяет использовать несколько потребителей для получения сообщений из долговременной подписки. Если вы используете общую долговременную подписку, используемой фабрике соединений не требуется идентификатор клиента. Для создания общей долговременной подписки вызовите метод JMSContext.createSharedDurableConsumer
, указав тему и имя подписки:
JMSConsumer consumer =
context.createSharedDurableConsumer(topic, "MakeItLast");
Смотрите Подтверждение сообщений, Использование долговременных подписок, Использование общих долговременных подписок и Отправка сообщений из сессионного компонента в MDB для примеров приложений Java EE, которые используют долговременные подписки.
Подписка на тему, созданная методом createConsumer
или createDurableConsumer
, может иметь только одного потребителя (хотя тема может иметь много). Несколько клиентов, использующих одну и ту же тему, по определению имеют несколько подписок на эту тему, и все клиенты получают все сообщения, отправленные в тему (если только они не фильтруют их с помощью селекторов сообщений).
Однако можно создать общую подписку, не являющуюся долговременной, на тему, используя метод createSharedConsumer
и указав не только пункт назначения, но и имя подписки:
consumer = context.createSharedConsumer(topicName, "SubName");
При общей подписке сообщения будут распределяться между несколькими клиентами, использующими одни и те же тему и имя подписки. Каждое сообщение, отправленное в тему, будет добавлено в каждую подписку (с учётом любых селекторов сообщений), но каждое сообщение, добавленное в подписку, будет доставлено только одному из потребителей этой подписки, поэтому оно будет получено только одним из клиентов. Общая подписка может быть полезна, если вы хотите разделить загрузку сообщений между несколькими потребителями в подписке, а не для того, чтобы только один потребитель в подписке получал каждое сообщение. Эта функция может улучшить масштабируемость клиентских приложений приложений Java EE и Java SE. (Бины, управляемые сообщениями, разделяют работу по обработке сообщений из темы среди нескольких потоков.)
См. Использование общих подписок, не являющихся долговременными для простого примера использования потребителей общих подписок, не являющихся долговременными.
Вы также можете создавать общие долговременные подписки с помощью метода JMSContext.createSharedDurableConsumer
. Для получения дополнительной информации см. Создание долговременных подписок.
Конечная цель приложения JMS — отправлять и получать сообщения, которые затем могут использоваться другими программными приложениями. Сообщения JMS имеют простой, но очень гибкий формат, позволяющий создавать сообщения, соответствующие форматам, используемым не-JMS-приложениями на гетерогенных платформах.
Сообщение JMS может состоять из трёх частей: заголовка, свойств и тела. Обязательным является только заголовок. В следующих разделах описываются эти части.
Полную документацию по заголовку, свойствам и телу сообщений, см. документацию по API интерфейса Message
. Список возможных типов сообщений см. в разделе Тело сообщения.
Здесь рассматриваются следующие темы:
Заголовок сообщения JMS включает несколько предопределённых полей, которые содержат значения, используемые как клиентами, так и поставщиками для идентификации и маршрутизации сообщений. Таблица 48-1 перечисляет и описывает поля заголовка сообщения JMS и значения этих полей. Например, каждое сообщение имеет уникальный идентификатор, который представлен в поле заголовка JMSMessageID
. Значение другого поля заголовка, JMSDestination
, представляет очередь или тему, в которую отправляется сообщение. Другие поля включают отметку времени и приоритет.
Каждое поле заголовка имеет get- и set- методы, которые описаны в интерфейсе Message
. Некоторые поля заголовка предназначены для установки клиентом, но многие устанавливаются автоматически с помощью метода send
, который переопределяет значения, установленные клиентом.
Таблица 48-1 Как устанавливаются значения полей заголовка сообщения JMS
Поле заголовка |
Описание |
Установлен |
|
Пункт назначения, на который отправляется сообщение |
Метод |
|
Режим доставки, указанный при отправке сообщения (см. Указание персистентности сообщения) |
Метод |
|
Время отправки сообщения плюс задержка доставки, указанная при отправке сообщения (см. Указание задержки доставки |
Метод |
|
Время истечения срока действия сообщения (см. Установка срока действия сообщения) |
Метод |
|
Приоритет сообщения (см. Установка приоритета сообщений) |
Метод |
|
Значение, которое однозначно идентифицирует каждое сообщение, отправленное провайдером |
Метод |
|
Время передачи сообщения провайдеру для отправки |
Метод |
|
Значение, которое связывает одно сообщение с другим. Обычно используется значение |
Клиентское приложение |
|
Пункт назначения, куда следует отправлять ответы на сообщение |
Клиентское приложение |
|
Идентификатор типа, предоставленный клиентским приложением |
Клиентское приложение |
|
Является ли сообщение повторно доставленным |
JMS-провайдер перед доставкой |
Вы можете создавать и устанавливать свойства для сообщений, если вам нужны значения в дополнение к тем, которые указаны в полях заголовка. Вы можете использовать свойства для обеспечения совместимости с другими системами обмена сообщениями или использовать их для создания селекторов сообщений (см. Селекторы сообщений JMS). Пример установки свойства, которое будет использоваться в качестве селектора сообщений, см. в разделе Отправка сообщений из сессионного компонента в MDB.
JMS API предоставляет некоторые предопределённые имена свойств, которые начинаются с JMSX
. Провайдер JMS должен реализовать только одно из них — JMSXDeliveryCount
(которое указывает количество доставок сообщения). Остальные свойства не обязательны. Использование этих предопределённых свойств, как и кастомных свойств в приложениях не обязательно.
JMS API определяет шесть различных типов сообщений. Каждый тип сообщения имеет свойственное ему тело сообщения. Эти типы сообщений позволяют отправлять и получать данные в различных формах. Таблица 48-2 описывает эти типы сообщений.
Таблица 48-2 Типы сообщений JMS
Тип сообщения |
Тело содержит |
|
Объект |
|
Набор пар имя-значение с ключами в виде объектов |
|
Поток неинтерпретируемых байтов. Этот тип сообщения предназначен для кодирования тела в соответствии с существующим форматом сообщения. |
|
Поток примитивных значений Java, заполняемый и читаемый последовательно. |
|
Объект |
|
Отсутствует. Состоит только из заголовка и свойств. Этот тип сообщения полезен, когда тело сообщения не требуется. |
JMS API предоставляет методы для создания сообщений каждого типа и для заполнения их содержимого. Например, для создания и отправки TextMessage
могут использоваться следующие операторы:
TextMessage message = context.createTextMessage();
message.setText(msg_text); // msg_text — объект типа String
context.createProducer().send(message);
На стороне потребителя сообщение приходит как обобщённый (generic) объект Message
. Затем можно привести объект к соответствующему типу сообщения и использовать специфичные методы для доступа к телу и извлечения содержимого сообщения (а также его заголовков и свойств, если необходимо). Например, могут быть использованы потоковые методы чтения BytesMessage
. Для получения тела StreamMessage
всегда нужно приводить сообщение к соответствующему типу.
Вместо приведения сообщения к конкретному типу может быть вызван метод getBody
у Message
с указанием типа сообщения в качестве аргумента. Например, можно извлечь TextMessage
как String
. В следующем фрагменте кода используется метод getBody
:
Message m = consumer.receive();
if (m instanceof TextMessage) {
String message = m.getBody(String.class);
System.out.println("Reading message: " + message);
} else {
// Обработка ошибки или сообщения другого типа
}
JMS API предоставляет удобные методы для создания и получения TextMessage
, BytesMessage
, MapMessage
или ObjectMessage
. Например, не нужно переносить строку в TextMessage
. Вместо этого можно отправить и получить строку напрямую. Например, можно отправить строку следующим образом:
String message = "This is a message";
context.createProducer().send(dest, message);
Можно получить сообщение, используя метод receiveBody
:
String message = receiver.receiveBody(String.class);
Можно использовать метод receiveBody
для получения сообщений любого типа, кроме StreamMessage
и Message
, при условии, что телу сообщения может быть назначен определённый тип.
Пустой Message
может быть полезен, если нужно отправить сообщение, которое является сигналом для приложения. Некоторые из примеров в главе 49 «Примеры JMS» отправляют пустое сообщение после отправки серии текстовых сообщений. Например:
context.createProducer().send(dest, context.createMessage());
Затем код потребителя может интерпретировать нетекстовое сообщение как сигнал о том, что все отправленные сообщения уже получены.
В примерах в главе 49 «Примеры JMS» используются сообщения типа TextMessage
, MapMessage
и Message
.
Сообщения, отправленные в очередь, остаются в очереди до их получения получателем сообщений для этой очереди. JMS API предоставляет объект QueueBrowser
, который позволяет просматривать сообщения в очереди и отображать значения заголовков для каждого сообщения. Чтобы создать объект QueueBrowser
, используйте метод JMSContext.createBrowser
. Например:
QueueBrowser browser = context.createBrowser(queue);
См. Просмотр сообщений в очереди для примера использования объекта QueueBrowser
.
Метод createBrowser
позволяет указать селектор сообщений вторым аргументом при создании QueueBrowser
. Для получения информации о селекторах сообщений см. Селекторы сообщений JMS.
JMS API не предоставляет механизма для просмотра темы. Сообщения обычно исчезают из темы, как только они появляются: если нет потребителей сообщений, которые их используют, провайдер JMS удаляет их. Хотя долговременные подписки позволяют сообщениям оставаться в теме, пока потребитель сообщений не активен, JMS не определяет никаких средств для их проверки.
Родительским классом всех проверяемых исключений в JMS API является JMSException
. Родительским классом всех непроверяемых исключений в JMS API является JMSRuntimeException
.
Общим способом обработки всех исключений, связанных с JMS API, является перехват JMSException
и JMSRuntimeException
.
Классы JMSException
и JMSRuntimeException
включают следующие дочерние классы, описанные в документации API:
IllegalStateException
, IllegalStateRuntimeException
InvalidClientIDException
, InvalidClientIDRuntimeException
InvalidDestinationException
, InvalidDestinationRuntimeException
InvalidSelectorException
, InvalidSelectorRuntimeException
JMSSecurityException
, JMSSecurityRuntimeException
MessageEOFException
MessageFormatException
, MessageFormatRuntimeException
MessageNotReadableException
MessageNotWriteableException
, MessageNotWriteableRuntimeException
ResourceAllocationException
, ResourceAllocationRuntimeException
TransactionInProgressException
,
TransactionInProgressRuntimeException
TransactionRolledBackException
,
TransactionRolledBackRuntimeException
Все примеры учебника перехватывают и обрабатывают JMSException
или JMSRuntimeException
, когда это уместно.
Назад | Вперёд | Содержание |