Здравствуйте, подскажите пожалуйста где можно достать материалы по курсу Кросс-платформенные и многозвенные технологии, о которых говориться, к примеру, в Лекции 2. Пример "Служба мгновенных сообщений" |
Технология Enterprise Java Beans. Часть 1
История и необходимость появления EJB
В данном разделе будут рассмотрены сеансовые (Session),объектные (Entity) и управляемые сообщениями (Message-driven) компоненты (Beans) EJB.Все примеры разработаны в среде Windows XP SP2.Несмотря на это, все используемые компоненты являются кросс-платформенными, так что примеры должны работать так же в Linux, Solaris или Mac OS X.Для демонстрации примеров необходимо следующее ПО:
- Java 5.0 (http ://java.sun.com/);
- Сервер приложений (контейнер EJB ) - открытый сервер приложений JBoss (http : //www .jboss. org/);
- СУБД - Oracle Database 9i.
- Среда разработки - Eclipse-WTP (Eclipse Web Tools Platform).Это модифицированная версия среды разработки Eclipse, в которую добавлена широкая поддержка веб-приложений и EJB. Скачать ее можно также на сайте Eclipse - http://www. eclipse. org/.
- Для Eclipse-WTP следует скачать еще плагин XDoclet (http : //xdoclet . sourceforge.net/). Он используется при развертывании объектных компонентов (Entity Beans) EJB в базе данных.
- Для примеров web -приложений, взаимодействующих через EJB с базой данных будут использоваться веб-сервер Apache (http : //www . apache.org/), и контейнер JSP Tomcat (http://tomcat. apache. org/).
Общее описание архитектуры EJB
Компонент Enterprise Bean
Серверные компоненты Enterprise Java Beans бывают трех принципиально разных типов:
- объектные компоненты (Entity Beans; точный перевод с английского -компоненты-сущности);
- сеансовые компоненты (Session Beans) и
- компоненты, управляемые сообщениями (Message-driven Beans).
Сеансовые и объектные компоненты являются серверными компонентами, основанными на RMI,к которым можно получить доступ при помощи распределенных объектных протоколов. Компоненты, управляемые сообщениями, появившиеся в EJB 2.0 - это асинхронные серверные компоненты, которые отвечают на асинхронные сообщения JMS и других протоколов.
Хорошее эмпирическое правило при конструировании компонентов EJB состоит в том, что объектные компоненты моделируют прикладные понятия, которые могут быть выражены существительными. Например, объектный компонент может представлять покупателя, часть оборудования, элемент инвентаря или даже место. Другими словами, объектные компоненты моделируют объекты реального мира. Эти объекты являются обычными постоянными записями в какой-либо базе данных.
Сеансовые компоненты являются расширениями клиентского приложения и отвечают за управление процессами и задачами. Для примера рассмотрим задачу о проектировании системы управления отелем. В качестве объектных компонентов в отеле могут выступать "Комната", "Постоялец", "Член персонала". Сеансовые компоненты отвечают за взаимодействие этих элементов и предназначены для управления различными видами деятельности, такими как заказ мест в гостинице. Сеансовый компонент "Бронирование места" может использовать компоненты "Постоялец" и "Комната", чтобы сделать заказ. Точно так же компоненты, управляемые сообщениями, отвечают за координацию задач, включающих другие сеансовые и объектные компоненты. Главное отличие между компонентами, управляемыми сообщениями, и сеансовыми компонентами состоит в том, как к ним осуществляется доступ. В то время как сеансовый компонент предоставляет удаленный интерфейс, определяющий, какие методы могут быть вызваны, компонент, управляемый сообщениями, этого не делает. Вместо этого он подписывается или прослушивает определенные асинхронные сообщения, обрабатывает их и управляет действиями, которые выполняют другие компоненты в ответ на эти сообщения. Например, компонент "Обработчик заказов", управляемый сообщениями, мог бы принимать асинхронные сообщения, возможно из существующей системы заказов, с помощью которых он бы мог координировать взаимодействие компонентов "Постоялец" и "Комната", для того, чтобы забронировать место в отеле.
Действия, которые принимают сеансовые компоненты и компоненты, управляемые сообщениями, по своей сути являются кратковременными: вы начали делать заказ, вы сделали часть работы, и на этом их действие заканчивается. Сеансовые компоненты и компоненты, управляемые сообщениями не соответствуют никаким объектам в базе данных. Понятно, что в процессе своей работы они оказывают влияние на базу данных, но через объектные компоненты. По крайней мере, такого подхода придерживаются при разработке больших распределенных приложений. В принципе, ничто не мешает из сеансового компонента сделать подключение к базе данных при помощи JDBC,и произвести необходимые операции с базой данных. Такой способ работы с базой данных через EJB будет рассмотрен далее в примерах.
Главное различие компонентов в том, что объектные компоненты имеют устойчивое состояние, а сеансовые компоненты и компоненты, управляемые сообщениями, моделируют взаимодействия и устойчивого состояния не имеют.
Классы и интерфейсы
Для реализации объектного или сеансового компонента необходимо определить:
- интерфейсы компонента,
- класс компонента и
- первичный ключ (только для объектных компонентов).
В данной главе будут сначала рассмотрены примеры сеансовых компонентов, разработанные в соответствии со спецификацией EJB 2.1.Компонент может иметь следующие интерфейсы:
- Удаленный интерфейс (Remote Interface) определяет прикладные методы компонента, доступные из приложений, внешних по отношению к контейнеру EJB,то есть прикладные методы, которые компонент представляет внешним приложениям. Удаленный интерфейс расширяет (extends) интерфейс javax.ejb.EJBObject.Внешние по отношению к EJB приложения вызывают методы удаленного интерфейса, а получают эти методы они при помощи домашнего интерфейса (Home Interface).
- Домашний интерфейс (Home Interface) определяет методы жизненного цикла компонента, доступные из приложений, внешних по отношению к контейнеру EJB,то есть методы создания новых компонентов, удаления и поиска существующих компонентов. Домашний интерфейс (Home Interface) расширяет (extends) интерфейс javax.ejb.EJBHome. Для того чтобы создать новый EJB или обратиться к существующему EJB,внешнее приложение должно сначала вызвать соответствующий метод create () его домашнего интерфейса (Home Interface).
- Локальный интерфейс (Local Interface) определяет прикладные методы EJB, которые могут использоваться другими компонентами, размещенными в том же контейнере EJB,но не внешними по отношению к контейнеру EJB приложениями. Он позволяет компонентам, находящимся в одном контейнере EJB,взаимодействовать без дополнительных затрат, связанных с применением протокола распределенных объектов, что повышает их производительность. Локальный интерфейс расширяет (extends) интерфейс javax.ejb.EJBLocalObject.Внешние по отношению к EJB компоненты, находящиеся в том же самом контейнере, работают с методами локального интерфейса, а получают эти методы они при помощи локального домашнего интерфейса (Local Home Interface)
- Локальный домашний интерфейс (Local Home Interface) определяет методы жизненного цикла компонента, доступные из компонентов, находящихся в том же контейнер EJB,то есть методы создания новых компонентов, удаления и поиска существующих компонентов. Это позволяет компонентам взаимодействовать без дополнительных затрат, связанных с использованием протокола распределенных объектов, что улучшает их производительность. Домашний интерфейс (Home Interface) расширяет (extends) интерфейс javax.ejb.EJBLocalHome.Для того чтобы создать новый EJB или обратиться к существующему EJB,; компонент, находящийся в том же контейнере EJB,должен сначала вызвать соответствующий метод его домашнего интерфейса (Home Interface).
Важным отличием между удаленным и локальным интерфейсом является то, что вызовы методов локального интерфейса не используют RMI и не генерируют RemoteException.Для корректной работы не обязательно предоставлять классу компонента все четыре интерфейса. К примеру, если компонент не используется никаким клиентским приложением (а нужен только другим компонентам, работающим под управлением того же EJB контейнера), то нет необходимости предоставлять удаленный интерфейс. То есть в зависимости от тех задач, которые решает данный компонент, ему может быть предоставлен либо локальные, либо удаленные, либо и те и другие интерфейсы.
- Для реализации компонентов, помимо интерфейсов, необходимо реализовать также
- Класс компонента.Классы сеансовых и объектных компонентов фактически реализуют прикладные методы и методы жизненного цикла компонента. Заметим, что класс компонента для сеансовых и объектных компонентов не реализует непосредственно (implements в терминах Java) ни один интерфейс компонента, однако он должен содержать методы, названия и списки параметров которых совпадают с названиями и списками параметров методов, определенных в соответствующих интерфейсах. Также этот класс должен содержать метод (или методы) ejbCreate(), соответствующие некоторым методам в обоих, домашнем (Home Interface) и локальном домашнем (Local Home Interface),интерфейсах. Объектные компоненты должны реализовывать интерфейс javax.ejb.EntityBean,а сеансовые компоненты - интерфейс javax.ejb.SessionBean.Компоненты, управляемые сообщениями, не используют ни один из интерфейсов компонентов, потому что к ним никогда не осуществляется доступ посредством вызовов методов из других приложений или компонентов. Вместо этого компоненты, управляемые сообщениями, содержат один метод onMessage (). Этот метод вызывается при прибытии нового сообщения.
- Первичный ключ.Это простой класс, предоставляющий указатель внутри базы данных. Первичный ключ необходим только объектным компонентам. Он должен реализовывать интерфейс java.io.Serializable.
У компонентов, управляемых сообщениями нет никаких компонентных интерфейсов, но, несмотря на это, они могут быть клиентами любых сеансовых или объектных компонентов и взаимодействовать с этими компонентами через их интерфейсы. Объектные и сеансовые компоненты, с которыми взаимодействует компонент, управляемый сообщениями, могут быть совмещенными, в этом случае он работает с их локальными компонентными интерфейсами, или они могут располагаться в разных адресных пространствах или контейнерах EJB - в этом случае используются удаленные интерфейсы. Спецификации EJB 1.1 и старше определяют удаленные (Remote) интерфейсы компонента в терминах протокола Java RMI-IIOP,который обеспечивает совместимость с CORBA.Для совместимости с типами Java RMI-IIOP поставщики EJB должны ограничить определение интерфейсов и параметров типами, соответствующими CORBA IIOP 1.2 (в соответствии со спецификацией CORBA 2.3.1).Локальные интерфейсы в EJB 2.0, EJB 2.1 и EJB 3.0 не являются интерфейсами Java RMI и не обязаны поддерживать IIOP 1.2 и использовать типы совместимые с протоколом Java RMI-IIOP.В Java RMI-IIOP определены три базовых типа объектов:
- byte, boolean, char, int, long, short, double, float ;
- объекты, реализующие интерфейс java .io.Serializable ;
- удаленные типы Java RMI - классы реализующие интерфейс java.rmi.RemoteException.
При попытке передать через удаленный метод объект, не относящийся к одному из трех типов, будет сгенерировано исключение java.rmi.RemoteException. Каждый метод в удаленном интерфейсе (Remote Interface) должен генерировать исключение java.rmi.Remote. Оно генерируется при проблемах с передачей данных в сети или невозможности найти требуемый сервер. Помимо этого разработчики могут использовать любые другие исключения при разработке компонент EJB.
Протокол Java RMI IIOP также накладывает ограничения на удаленные интерфейсы. Этих ограничений много, но реально используется только два из этих ограничений.
- Сериализуемые объекты (Serializable) не должны реализовывать (implement) интерфейс java.rmi.Remote.
- Удаленный интерфейс не может реализовывать два и более интерфейса, у которых есть методы с одинаковыми именами. Удаленный интерфейс может перегружать (overload) свои собственные методы и расширять (extends) удаленный интерфейс с перегруженными (overloaded) методами.
Существует много инструментальных средств, которые позволяют сильно упростить работу с EJB.В частности одним из средств, которое также предоставляет платформа Eclipse-WTP,является средство создания связей между объектными компонентами и базой данных. В Eclipse-WTP это делается при помощи пакета XDoclet.Каким образом это делается, будет рассмотрено далее.
Сеансовые компоненты
Сеансовые компоненты могут быть с состоянием (Stateful) и без состояния (Stateless).Компоненты с состоянием при использовании клиентом поддерживают состояния диалога (Conversational state).Состояние диалога не заносится в базу данных, оно сохраняется в памяти все время, пока клиент использует сессию. Состояние сеансового компонента может измениться при вызове любого его метода, и это изменение может привести к последующим вызовам методов. Состояние диалога поддерживается только до тех пор, пока клиентское приложение активно использует компонент. Если клиент отключается или освобождает компонент, его состояние теряется навсегда. Сеансовый компонент с состоянием не может использоваться несколькими клиентами. Он выделяется для одного клиента на все время своей жизни.
Сеансовые компоненты без состояния (Stateless Session Bean) ни поддерживают никакого состояния диалога. Каждый метод полностью независим и пользуется только данными, переданными через его параметры. Сеансовые компоненты без состояния (Stateless Session Bean) имеют более высокую производительность, с точки зрения пропускной способности и потребления ресурсов, чем объектные компоненты и сеансовые компоненты с состоянием (Stateful Session Bean),поскольку для обслуживания большого количества клиентов требуется всего несколько экземпляров сеансового компонента без состояния. При создании сеансового компонента без состояния (Stateless Session Bean) контейнер EJB выполняет следующую последовательность действии:
- При помощи метода Class.newInstance () создается экземпляр класса компонента.
- Вызывается метод SessionBean.setSessionContext( SessionContext context). При помощи этого метода экземпляру компонента передается ссылка на объект класса EJBContext, предоставляющий интерфейс для взаимодействия с контейнером EJB (в частности, в этом объекте есть метод lookup(), позволяющий искать другие объекты по путям JNDI).
- Вызывается метод ejbCreate (). У сеансовых компонентов без состояния (Stateless Session Bean) этот метод не имеет параметров. В этом методе компонент может создать подключения к базам данных и к другим ресурсам.
- Контейнер помещает созданный компонент в пул готовых компонентов.
При запуске контейнер обычно создает несколько экземпляров сеансовых компонентов без состояния (Stateless Session Bean).При необходимости контейнер может либо создавать новые экземпляры, либо удалять ненужные. При удалении компонента из пула готовых компонентов вызывается метод ejbRemove(). В этом методе следует закрыть все открытые подключения к различным ресурсам.
То, каким образом и когда контейнер EJB должен создавать и удалять экземпляры сеансовых компонентов без состояния, не описывается спецификацией EJB. В каждом из существующих контейнеров EJB этот механизм реализован по-разному.
Сеансовые компоненты с состоянием создаются тогда, когда клиент запрашивает метод create() у домашнего интерфейса (Home Interface).После этого созданный компонент переходит в состояние готовых методов. В этом состоянии он готов выполнять свои методы, вызываемые клиентом через удаленную ссылку. Компонент в это время может хранить открытые ресурсы (базы данных, TCP/IP сессии и др.), а также хранить посредством своих переменных определенное состояние, которое может изменяться при вызове клиентом различных его методов. Последовательность методов, вызываемых контейнером при создании сеансового компонента с состоянием аналогична последовательности методов при создании сеансового компонента без состояния. Только компонент в конце переходит в состояние готовых методов, а не в пул готовых компонентов.
При нахождении компонента в состоянии готовых методов, он может либо оставаться в этом состоянии, либо переведен в пассивное состояние (при этом будет вызван метод ejbPassivate () - см. далее), либо быть удаленным. То, при каких условиях компонент будет переведен в пассивное состояние, в каждом из существующих контейнеров определяется по-разному. При активизации компонента (вызывается метод ejbActivate () - см. далее), компонент переводится из пассивного состояние в состояние готовых методом. При этом значение всех внутренних переменных и состояние диалога сохраняется.
Компонент может быть удален при вызове соответствующего метода remove() домашнего интерфейса, либо контейнером после определенного промежутка времени, в течение которого компонент "бездействовал". Компонент не может быть удален при выполнении транзакции. При удалении у компонента будет вызван метод ejbRemove().