В предыдущих статьях («Мир ПК», №11, 12/06, 1, 2/07) мы рассматривали вопросы взаимодействия с серверами БД с помощью SQL и веб- и EJB-компонентов. Тогда речь шла о синхронном взаимодействии клиентов и серверов.
«Синхронное взаимодействие» в первоначальном понимании означало, что при передаче информации (в том или ином виде) от одного приложения к другому приложение-отправитель («клиент») переходило в режим ожидания отклика на запрос от приложения-получателя («сервера»). Напротив, под «асинхронностью» понималась возможность продолжить работу, не дожидаясь получения ответа.
После того как широкое распространение получили операционные среды с наличием простых и удобных средств разработки многопоточных приложений, смысл понятий «синхронное» и «асинхронное» взаимодействие изменился — просто потому, что в многопоточной среде прежнее толкование потеряло смысл.
В настоящий момент под «асинхронным взаимодействием» понимается режим передачи информации, при котором между отправителем и получателем находится «посредник», который не просто обеспечивает передачу сообщения, но и решает некоторые другие задачи, например:

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

Синхронный и асинхронный режимы взаимодействия могут быть реализованы с использованием различных транспортных протоколов. Применительно к Java-технологиям очень часто синхронный вызов называют «вызовом в стиле RPC» (Remote Procedure Call), а асинхронный — «отправкой сообщения» (по-английски — messaging).
Асинхронное взаимодействие в стиле messaging занимает важное место в распределенных системах. Пожалуй, основными достоинствами такого способа взаимодействия являются:

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

На уровне использования языка Java формализацией интерфейсов такого взаимодействия является технология JMS — Java Messaging Service.

Основные понятия JMS
Основная идея использования этой технологии заключается в том, что разработчики создают только клиентские приложения, часть из которых является отправителями, а часть — получателями сообщений. Конечно, можно и отправлять, и получать сообщения в одном приложении. Сервер (его часто называют message broker) обычно создается крупными компаниями — IBM, Tibco, Sonic, и прикладные разработчики просто используют его подобно веб-серверам или серверам БД.
Как правило, перед началом работы программной системы, использующей JMS, на стороне сервера создаются так называемые администрируемые объекты. Это, во-первых, фабрики соединений (connection factories), а во-вторых, «целевые» объекты двух видов — топики (topics) и очереди (queues). Основное отличие топиков от очередей состоит в том, что топики размножают сообщение для всех, кто желает его получить, а очередь является просто каналом передачи сообщения единственному потребителю — первому, кто успел. Соответственно очереди реализуют программную модель «отправитель—получатель» (sender—receiver), а топики — «издатель—подписчик» (publisher—subscriber).
Получатель сообщений — при использовании как топиков, так и очередей — может извлекать сообщения из нужного целевого объекта в двух режимах — синхронном и асинхронном. В данном случае термины «синхронный» и «асинхронный» характеризуют режим получения сообщения в приложении-получателе.
 В синхронном режиме программа-получатель явно вызывает для специального объекта-получателя, сопоставленного с требуемым целевым объектом, специальный метод (receive()). Этот метод возвращает сообщение, если оно доступно. Если сообщения нет, то вызов этого метода блокирует поток выполнения команд и программа ждет прихода сообщения.
В асинхронном режиме получатель реализует callback-метод onMessage() специального интерфейса MessageListener. Разработчик создает класс, реализующий данный интерфейс, затем — экземпляр этого класса и сопоставляет его с нужным целевым объектом. При приходе сообщения происходит вызов и выполнение кода метода onMessage().
Администрируемые объекты обычно создаются администратором брокера сообщений с использованием поставляемых разработчиками сервера специальных утилит администратора. В большинстве случаев такие объекты являются глобальными, т.е. доступны для различных приложений, а доступ к ним производится с использованием службы имен — JNDI.
Важно понимать, что JMS обеспечивает доставку сообщений только целевым объектам, а не «истинным» потребителям. Задача правильного получения событий в программе от топика или из очереди может быть весьма нетривиальной.
Важнейшим понятием JMS является сессия (session). Проще всего трактовать сессию как контекст потока, в котором выполняется передача сообщений. Фабрикой сессий является соединение (connection). В свою очередь сессия играет роль фабрики для объектов — отправителей сообщений, объектов — получателей сообщений и самих сообщений. Отправители, получатели событий и сами события представляют собой обычные локальные объекты Java. При передаче события (сообщения) выполняется его сериализация — опять-таки по обычным правилам Java.
В более сложном случае — с использованием распределенных транзакций — сессия выступает как получатель сообщений и одновременно как их диспетчер.
 
JMS и Geronimo/WAS CE
Использование JMS в Geronimo/WAS CE имеет определенную специфику (которая сохранится до появления версии WAS CE 1.2). Эта специфика связана с получением доступа к администрируемым объектам JMS. Суть этой проблемы (если это является проблемой) заключается в следующем: стандартный подход к применению JMS API основан на использовании глобальных (в смысле — общедоступных) администрируемых объектов. Предполагается, что они создаются администратором системы, а программный код просто использует их, причем для поиска применяется типовой для J2EE подход — использование службы имен JNDI.
Философия же Geronimo/WAS CE построена на отказе от глобальных контекстов службы имен с целью повышения производительности системы.
Это означает, что возникают определенные трудности для получения объектных ссылок на администрируемые объекты вне единого пространства XML-дескрипторов, другими словами, вне EAR-архивов J2EE.
Проблема осознается разработчиками. Конечно, радикально вопрос решается поддержкой глобального контекста JNDI и автоматической регистрацией объектных ссылок на администрируемые объекты JMS в этом контексте при развертывании этих объектов на сервере. Поддержка глобального контекста обещана в версии 1.2. Пока этого нет, используется паллиативное решение. При запуске сервера устанавливается (для версий 1.0.x сервера) конфигурация с именем geronimo/activemq/1.0/car, в которой создаются специальный экземпляр службы имен с глобальным контекстом и несколько администрируемых объектов, причем в их число входят три фабрики соединений. Получить доступ к этим объектам можно, например, с помощью такого кода:

Properties props = new Properties();

props.setProperty(Context.INITIAL_CONTEXT_FACTORY,
“org.activemq.jndi.ActiveMQInitialContextFactory“);
props.setProperty(Context.PROVIDER_URL, “tcp://localhost:61616“);

     Context initContext = new InitialContext(props);

Если после этого для полученного контекста вызвать метод list(), например:

NamingEnumeration enum = initContext.list(““);
while (enum.hasMore())
     {
          Object o = enum.next();
          System.out.println(o);
     }

то выводимая информация будет иметь следующий вид:

QueueConnectionFactory: org.activemq.ActiveMQConnectionFactory
dynamicTopics: org.activemq.jndi.ActiveMQInitialContextFactory$2
ConnectionFactory: org.activemq.ActiveMQConnectionFactory
TopicConnectionFactory: org.activemq.ActiveMQConnectionFactory
dynamicQueues: org.activemq.jndi.ActiveMQInitialContextFactory$1

Как видно, созданы три фабрики соединений (одна — общего назначения, одна — только для топиков и одна — только для очередей). Кроме этих администрируемых объектов созданы два дочерних контекста — dynamicTopics и dynamicQueues. С точки зрения прав доступа JNDI эти контексты доступны только для чтения. Тем не менее поместить в них информацию (объектные ссылки на очереди и топики) все-таки можно.
Об использовании этих фабрик соединений и контекстов (dynamicTopics и dynamicQueues) будет рассказано ниже.
Самое важное, что надо иметь в виду при использовании JMS вместе с WAS CE: для создания администрируемых объектов нужно создать RAR-модули (коннекторы) и соответствующие им конфигурации GBeans, а доступ к ресурсам — администрируемым объектам — задается с помощью XML-дескрипторов. Это означает, что все делается быстро и просто только при использовании JMS между различными компонентами системы в составе одного EAR-архива. В противном случае разработчик должен сам обеспечить доступ к объектам JMS. В каждом конкретном случае это не представляет большой сложности.

Запуск брокера сообщений в WAS CE
WAS CE позволяет создавать и запускать несколько различных брокеров сообщений. В частности, можно использовать WebSphere MQ или другую коммерческую реализацию. По умолчанию в комплект поставки входит брокер ActiveMQ, созданный в рамках OpenSource-проекта. Он находится в конфигурации geronimo/activemq-broker/1.0/car, которая запускается по умолчанию при старте сервера. Файл конфигурации сервера .varconfigconfig.xml содержит следующее описание параметров этой конфигурации:



0.0.0.0
61616

 

Брокер сообщений ActiveMQ поддерживает различные протоколы взаимодействия. Консоль администратора (см. рисунок) позволяет увидеть список протоколов и соответствующие параметры настройки (в колонке навигации выбран элемент JMS Server).

Консоль администратора 

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


О том, как создавать администрируемые объекты с помощью консоли администратора, вы сможете прочитать в полной версии статьи на «Мир ПК-диске».