[an error occurred while processing this directive]
Предисловие
Данная статья предназначена, как это следует из названия, для первичного ознакомления с одной из ключевых технологий 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 затем пересылает его адресату.
Рис. 1
MOM позволяет избавиться от перечисленных в п.2 недостатков.
Приложение, пославшее сообщение, не должно ждать ответа, и может продолжать свою текущую деятельность.
Ни приложение, посылающее сообщение, ни адресат данного сообщения не обязаны бать активными в одно и то же время. Если адресат сообщения не активен, то MOM гарантирует, что сообщение будет доставлено как только адресат станет активным.
Компоненты системы не связаны напрямую друг с другом (decoupled), а потому возможно перенесение компонентов с одного хоста на другой в runtime без ущерба для работоспособности системы.
Модели обмена сообщениями
Существует две "основных" модели обмена сообщениями:
Point-to-point модель применяется, когда одному или нескольким компонентам (так называемые senders) необходимо посать сообщение одному компоненту-адресату (receiver).
Модель основана на понятии message queue. Sendersпосылают сообщения в queue, а Receiver читает сообщения из queue.
Рис. 2
Часто говорят, что в point-to-point модели есть один и только один receiver. Однако это не совсем верно. Может существовать несколько receivers, присоединенных к одной и той же queue. Но MOMдоставит сообщение только одному из них. Какому именно – зависит от реализации. Некоторые MOM доставляют сообщение первому зарегистрированному receiver, в то время как существуют реализации, осуществляющие round-robin.
Publish-subscribe модель применима, когда одному или нескольким компонентам (publishers) необходимо послать сообщение одному или нескольким компонентам-адресатам (subscribers). Данная модель основана на понятии message topic.
Publishers посылают сообщения в topic, и все subscribersданного topic получают эти сообщения.
Рис.3
Какую именно модель использовать – это зависит от того, какой вы видите вашу систему во-первых, и какой 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– сообщение. О типах сообщений будет сказано ниже.
Использование Point - to - Point модели в
JMS
Итак, приступим к созданию простейших 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<1000;i++){
//Создадим простейшее текстовое сообщение
textMessage.setText("Hi! It's my message number "+i);
//И пошлем его
sender.send(textMessage);
try{
Thread.sleep(sendInterval);
}catch(Exception se){
System.out.println("Got an exception "+se.getMessage());
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
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.
import javax.jms.*;
import javax.naming.*;
//Обратите внимание, что класс реализует интерфей MessageListener
public class AsyncReceiver implements MessageListener{
public AsyncReceiver(){
}
//Метод onMessage интерфейса MessageListener будет вызван
//Consumer'ом для обработки поступившего сообщения
public void onMessage(Message message){
try{
TextMessage textMessage = (TextMessage)message;
System.out.println("Got a message : "+textMessage.getText());
}catch(JMSException jmse){
jmse.printStackTrace();
}
}
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);
}
QueueReceiver receiver = session.createReceiver(queue);
con.start();
AsyncReceiver async = new AcyncReceiver();
//Зарегистрировать новый AsyncReceiver обьект как
//MessageListener дляreceiver
receiver.setMessageListener(async);
//А далее - делать что-либо, не ожидая сообщения.
//Сообщение будет обработано, как только придет.
//Для примера будем эмулировать бурную деятельность –
//"спать"!
Thread.sleep(100000000);
}catch(Exception e){
e.printStackTrace();
}
}
}
Как видно из примеров, JMS API достаточно прост. В следующем разделе будет представлена pub-sub модель. Изменив point-to-point код всего в нескольких местах, Вы получите работающее pub-sub приложение.
Использование Pub-Sub модели в JMS
Pub-Sub publisher :
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<1000;i++){
textMessage.setText("My topic message number"+i);
//Посылаем сообщение
publisher.publish(textMessage);
try{
Thread.sleep(sendInterval);
}catch(Exception ie){
ie.printStackTrace();
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
Как видите, изменения в коде незначительны.
Pub-Sub subscriber:
Как и в случае 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:
textMessage.setIntProperty("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 в том, что посылка сообщения может быть частью транзакции.
Существует два подхода в использовании транзакций совместно с JMS. Один применим только внутри JMS, другой может быть использован для включения не только JMS но и, например, JDBC - запроса, в состав той же транзакции.
Первый подход заключается в использовании 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.
Заключение
В заключение приведу несколько ссылок на доступные в сети ресурсы по данной тематике.
http://java.sun.com/products/jms/
http://www.jguru.com/ faq/home.jsp?topic=JMS
http://www.theserverside.com/ home/index.jsp
http://www.devx.com/upload/free/features/ javapro/2001/01jan01/ jm0101/jm0101.asp
http://www.devx.com/upload/free/features/ entdev/2000/06jun00/rg0006/rg0006.asp
http://www.prismtechnologies.com/English/ Downloads/DownloadsFrame.html
http://e-docs.bea.com/wls/ docs61/jms/index.html
http://www-4.ibm.com/ software/ts/mqseries/api/mqjava.html
http://www.iplanet.com/products/ iplanet_message_queue/home_message_queue.html
http://www.talarian.com/ products/jms/index.shtml
http://www.fiorano.com/ products/products.htm
http://www.objectweb.org/joram/
Об
авторе
Алексей Букавнев, Lead Software Engineer-Consultant in NOKIA Mobile Phones, Mobile
Software Unit (ex Middleware and Applications development Group), Irving, TX, USA
EXT-Aleksey.Bukavnev@nokia.com
< Вернуться на caйт :: Copyright © 1999 — 2010, IT • archiv. |