![]() |
|
||
|
|
|
How-to по Enterprise Java Beans(Валентин О. Ключник) Содержание
1. Введение - How do you do?- Как Вы это делаете? В данном how-to мы рассмотрим создание компоненты EJB. Заметим, что в спецификации EJB наличествует смешение обозначений: аббревиатура EJB используется как для обозначения компоненты Enterprise JavaBean, так и для обозначения архитектуры Enterprise JavaBeans. Также стоит заметить, что спецификация J2EE четко разделяет роли специалистов при работе с сервером приложений, соответствующим J2EE спецификации. В этом how-to рассмотрим роль именно разработчика EJB и самую малость коснемся роли сборщика приложения, основываясь на спецификации EJB 1.1, входящей в состав спецификации J2EE версии 1.2.1 Release от 23 мая 2000 г. Задача любого how-to - показать просто и наглядно, а как же именно реализуется та или иная концепция. По его прочтении у благодарного читателя из мешанины спецификаций и аббревиатур должно сложиться более четкое впечатление об интересующем вопросе, чем собственно до его прочтения. Итак, попытаемся реализовать эти светлые идеи. Как правило богатая практика дополняет сухую теорию, поэтому каждый раздел по возможности снабжен примерами. Место в тексте, ссылающееся на пример, обозначено как (рисунок обозначения примеров). 2. Архитектура EJB.Схематически структуру взаимодействия всех элементов в трехуровневой архитектуре, построенной с использованием архитектуры Enterprise JavaBeans, роль и место компоненты EJB, можно представить в виде, показанном на рис.1.
Рис. 1 Архитектура EJB и место EJB-компоненты в сервере приложений. Как следует из все той же любимой нами спецификации, основными отличительными особенностями компоненты EJB являются:
Итак, написание компоненты EJB, как следует из спецификации, состоит из четырех этапов. "Начнем с начала и закончим в конце", как любила говорить гусеница из "Алисы" Л.Кэррола. 2.1 Определение home-интерфейса & получение Home-Object.Home-интерфейс определяет методы для нахождения, создания и удаления экземпляров классов EJB клиентом и по общепринятой практике определяется интерфейсом FooHome, где Foo - название сущности бина. Производителем EJB-контейнера должны быть поставлены разработчику средства, которые автоматически генерируют ему код реализации home-интерфейса, т.н. Home-Object. При этом Home-интерфейс должен наследовать интерфейс javax.ejb.EJBHome. И при этом наследовать методы create(), find() и remove(), каждому из которых соответствуют методы ejbCreate(), ejbFind() и ejbRemove(), реализованные в Home-Object'е. Также в нем определяется метод getEJBMetaData() для получения метаданных данного бина. Note: Также при кодировании entity-бинов разработчику можно определить в Home-интерфейсе методы для поиска этого бина, которые позволят EJB клиенту определять местонахождение имеющихся entity-бинов в соответствии с их идентификаторами. 2.2 Определение remote-интерфейса.Remote-интерфейс определяет бизнес-методы компоненты EJB в интерфейсе Foo. EJBObject получит код реализации, сгенерированный для этого интерфейса инструментальными средствами контейнера. Заметим, что имена методов и их сигнатуры, указанные в remote-интерфейсе, должны в точности соответствовать именам и сигнатурам бизнес-методов, указанным в самом бине, в отличие от home-интерфейса, когда совпадают только сигнатуры методов, а их имена отличаются. Заметим, что по правилам RMI аргументы и возвращаемые типы каждого метода должны быть Serializable и в качестве одного из посылаемых исключений все методы должны посылать java.rmi.RemoteException. 2.3 Кодирование бина.- Лампочка, значит, Ну, очевидно, что класс, где реализуется бизнес-логика, должен реализовывать методы, объявленные в remote-интерфейсе. По сложившейся практике это делается в классе FooEJB. При управляемой контейнером персистентностью мы бы этим и ограничились, но когда эта ответственная задача ложится на бин, то код управления приходится реализовать именно здесь. Существует несколько подходов к разделению этих в принципе различных по своей природе вещей (бизнес-методы и методов управления персистентностью): а) В классе FooEJB определяются смешанно и бизнес-методы и методы хранения, но делается отдельный класс FooDAO (Data Access Objects), в котором инкапсулируется вся логика работы с СУБД. Здесь разделяются функции работы непосредственно с базой и функции бина. б) Делается абстрактный класс FooEJB, в котором объявляются и бизнес-методы и методы хранения. Затем делается класс FooCMP (Container Managed Persistence), в котором определяются бизнес-методы и который можно давать контейнеру в случае реализации CMP и делается FooBMP (Bean Managed Persistence), в котором внимательный читатель неуловимо уловил реализацию методов управления персистентностью. Если смотреть на методы управления персистентностью, то право на существование имеют оба подхода, но как правило, метод CMP дает в распоряжение программиста довольно скудные ресурсы (на уровне сохранения в одну таблицу линейных данных), что хорошо для примеров, но не для практики. Вероятно, поэтому метод BMP оказался более так сказать, живуч. 2.4 Деплоймент "бина".Деплоймент (deployment) бина есть не что иное, как описание установки (развертывания) enterprise-приложения на сервер приложений. В составе enterprise-приложения обычно различают: а) EJB-составляющую, т.е. набор бинов; б) WWW-составляющую, набор WEB-приложений, сервлетов, JSP, файлов с изображениями, etc. в) Клиентский код, Java-приложения работающие с EJB-составляющей. В этой фазе разработки бина разработчик выступает в роли "сборщика приложения" ("Application Assembler") и делает специальные XML-файлы развертывания (deployment descriptors), где с использованием специального DTD описывает, как именно enterprise-приложение должно быть установлено на сервер приложения. Обычно сам процесс деплоймента представляется набором XML-файлов и архивов: EJB DeploymentDescriptor (DD), WAR DD и EAR DD. Для примера можно посмотреть раздел Ресурсы. Заметим, что обычно у каждого порядочного AppServer'а есть специальный софт, Deployment Tool, с помощью которого разработчик может визуально отслеживать процесс и файл деплоймента. Хотя никто не мешает делать то же самое руками. Как говорится, кто любит дыню, а кто свиной хрящик. Одним из положительных моментов технологии EJB является тот, что частично такие вещи, как обеспечение транзактивного поведения, защиту информации, обработка нитей etc. берет на себя компания-разработчик сервера приложений. Разработчик EJB может сконцентрировать свое внимание на бизнес-логике работы своего "бина". Я не случайно упомянул слово "частично" , так как иногда все-таки есть необходимость реализовать транзактный механизм самому. 3. Типы бинов.Если бы рыба была собакой, у ней водились бы блохи. По спецификации EJB компоненты EJB бывают двух типов: session EJB и entity EJB. Для начала разговора про эти два типа обычно предлагают понять концепцию активизации (activation) и перевода в пассивное состояние (passivation). Перевод в пассивное состояние есть сохранение состояния бина в базе данных для последующего восстановления этого состояния. Активизация же есть суть это самое восстановление состояния бина (набора атрибутов) из персистентной (долговременной) базы данных. 3.1 Entity-бины.Entity-бины представляют собой бизнес-правила, оперирующие с перманентными (хранящиеся постоянно) данными в базе данных, причем к этим данным в условиях решаемой задачи должны иметь доступ многие пользователи. Каждому Entity-бину соответствует свой первичный ключ, по которому он может быть однозначно определен клиентом. Также Entity-бин имеет всегда какое-либо состояние (набор величин атрибутов, определяющих данный Entity-бин), которое может быть зафиксировано и сохранено, а затем и восстановлено. Разделяют персистентность, управляемую контейнером (Container-managed persistence) и персистентность, управляемую самим бином (Bean-managed persistence). Отличие состоит в том, кто ответственен за сохранение состояния бина: в первом случае это контейнер EJB, во втором - сам бин. Первое более универсально и требует меньших затрат от разработчика EJB, второе требует написания отдельного кода в бине и используется, очевидно, когда первый способ по каким-либо причинам (скорость, необходимость специальной функциональности при сохранении состояния бина, etc.) разработчика не устраивает. Жизненный цикл Entity-бина состоит из трех состояний: а) Бин не существует; б) Бин находится в "обобщенном" (pooled) режиме, куда сервер приложений по спецификации переводит набор бинов, задавая им метод setEntityContext(). Таким образом, в этом состоянии бин получил кое-какие признаки своего класса, но ещё не идентифицирован с определенным полем в СУБД; в) Бин находится в "готовом" (ready) режиме, он идентифицирован с конкретными данными в базе данных. Заметим, что Entity-бинам не страшны такие приятные неожиданности, как сбои в системе или виртуальной Java-машине (JVM). Такие ситуации приведут только к откату (rollback) текущей транзакции и не уничтожат сам бин, который восстановится позднее при включении системы и JVM, и тем более не изменят ссылку, по которой клиент обращается к бину через JNDI. 3.1.1 Определение ключевого класса.Сервер EJB одним из требований для entity-бинов ставит наличие ключевого класса (primary key class), с открытым элементом или набором элементов исходных данных, причем эти элементы (и сам ключевой класс, соответственно) однозначно позволяют идентифицировать entity-бин в персистентной базе данных. К нему определяется ряд требований: а) Уникальность соответствия Entity-бина записи в базе; б) Реализации java.io.Serializable (для передачи по RMI); в) Реализации метода hashCode, который возвращает хеш-код ключа; г) Реализации метода сравнения ключевых классов equals(Object other). 3.2 Session-бины.Session-бин создается клиентом, выполняет операции от его лица и в большинстве случаев существует только когда клиент соединен с сервером приложений. Разделяют два вида session-бинов: не имеющие состояния (Stateless session beans) и имеющие состояние (Statefull session beans). Различие, как видно из названия, первые не имеют определенного нуждающегося в сохранении состояния, а вторые имеют. Соответственно, первые не нуждаются в переводе из активного в пассивное состояние и обратно и используются для работы с большим числом клиентов. Вторые более тонкие и капризные, требуют операций активации и сохранения состояния и для каждого клиента создается отдельный такой бин. Жизненный цикл Statefull Session-бина состоит из: а) Бин не существует; б) Бин готов к работе; в) Пассивный режим. В эту ловушку statefull бины попадают исключительно по прихоти сервера приложений, когда он решит перенаправить бин из памяти в вторичное хранилище. Код извне имеет доступ только к методам create и remove. Жизненный цикл Stateless Session-бина состоит из: а) Бин не существует; б) Бин готов к работе. Как мы видим, во втором случае сервер приложений совсем не заботится о сохранении состояния бина, да это и не нужно по определению. Stateless, как-никак. И при сбоях в системе или JVM session-бины уничтожаются. Т.е. срок их жизни ограничен временем соединения клиента с сервером приложений и ... временем бессбойной работы системы и JVM. По сути дела, session-бины являются закрытыми ресурсами, использующимися только клиентами, которые их создали, и по этой причине прячут свой собственный идентификатор от клиента и остается анонимным, в отличие от entity-бина, который может быть однозначно идентифицирован с помощью первичного ключа. 4. Пример реализации библиотеки на EJB.В литературе по EJB обычно в качестве примера дается всем уже успевший поднадоесть WWW-магазин. Рассмотрим для разнообразия систему удаленного доступа к, скажем, библиотеке. Паркуа бы и не па? Сконцентрируемся на показании характерных мест использования EJB, при этом не усложняя. Итак, сервер приложений в нашем случае берет на себя выполнение следующих функций:
В качестве клиента системы используется WWW-браузер. Таким образом, система состоит таким образом из двух Session-бинов, UserOrderEJB и CatalogEJB, которые отвечают соответственно за выбор книг пользователем и произведение заказа и структурированный вывод информации о книгах библиотеки (См. Рис.2) и одного Entity-бина BookEJB, который представляет собой запись в таблице книг.
Рис. 2 Пример построения простой библиотеки с использованием архитектуры EJB. Для WWW-клиента системы к этому набору надо добавить сервлет отображения информации UserOrderServlet. Спешу напомнить, что в этом разделе мы стараемся внешне описательно пройтись по всем методам бинов и акцентировать внимание читателя на некоторых важных деталях. Все остальное можно почерпнуть из детального анализа исходных текстов, благо их можно скачать здесь и смею заверить, они снабжены довольно подробными комментариями, на английском языке. 4.1 Реализация Home -интерфейса.Возьмем для примера наш любимый BookEJB. Для него home-интерфейс будет выглядеть следующим образом.
/**
* Home interface for BookEJB.
*/public interface BookHome extends EJBHome {
/**
* Create instance of BookBean.
* @throws CreateException An input parameter
* is invalid.
*/ public Book create(BookPK bookId, int themeId, String author, String title, int count)
throws CreateException, RemoteException;
/**
* Check if such primary key exists in DB
* throws FinderException The DB row for the
* requested entity bean is cannot be found.
*/ public Book findByPrimaryKey(BookPK primaryKey)
throws FinderException, RemoteException;
}
Заметим, что метод create() соответствует методу ejbCreate() в entity-бине, а метод findXXX() соответственно методу ejbFindXXX(). 4.2 Реализация Remote-интерфейса.Для Entity-бина BookEJB remote-интерфейс будет состоять из пар get /set, которые работают с полями бина. Для Session-бина UserOrderEJB remote-интерфейс будет состоять из более интересных компонент, там наличествуют методы: а) Добавления книги в заказ. Здесь в вектор пользовательского заказа добавляется книга, причем на уровне этого бина регулируются бизнес-правило, гласящее: нормальный пользователь на руки не возьмет больше одного экземпляра данной книги; б) Удаления книги из заказа; в) Получения вектора заказа. Возвращается вектор выбранных пользователем книг; г) Формирования заказа. Здесь формируется набор записей в таблицу владения книгами.Note: Причем специально для показывания характерных деталей в магазине автор не стал вводить набор ролей пользователей, самих пользователей, считается, что пользователь один. Для Session-бина CatalogEJB remote-интерфейс будет состоять из: а) Получения массива записей начиная с определенной позиции и заданной длинны; б) Получение общей численности книг разнородных книг в библиотеке. 4.3 Реализация бина.Здесь интереснее всего в качестве комментария рассмотреть Entity-бина BookEJB. Он реализует набор пар get/set, которые устанавливают/получают значения его полей. Также реализованы методы управления персистентностью: а) ejbCreate(BookPK BookPK, :) Создание экземпляра бина в базе. Ему соответствует метод insertRow в классе BookDAO, инкапсулирующем логику работы с СУБД. Заметим, что одним из параметров создания бина идет BookPK - ключевой класс для нашего Entity-бина. б) ejbRemove() Удаление экземпляра бина в базе по первичному ключу. Ему соответствует метод insertRow в классе BookDAO; в) Методы ejbLoad() и ejbStore().Им соответствуют методы selectRow и updateRow соответственно в классе BookDAO. Стоит отметить, что при указании типа транзакции required над бизнес-методом бина, перед заданием переменной и после её получения контейнер автоматически вызывает эти методы для чтения и соответственно сохранения состояния бина из базы. Посмотрите по записям в логе, что эти методы вызываются именно в этой последовательности. г) BookPK BookPK ejbFindByPrimaryKey(BookPK BookPK) Нахождение экземпляра бина в базе. Ему соответствует метод isRowExists в классе BookDAO. д) getDBConnection Получает соединение к СУБД из пула соединений EJB-контейнера. В Session-бинах происходит реализация бизнес-функций, описанных в разделе 4.3, а также инициализация при создании ссылок на другие бины и инициализация внутренних переменных. 4.4 Определение ключевого класса.В нашем случае ключевой BookPK класс для BookEJB выглядит следующим образом.
public class BookPK implements Serializable {
public int id;
public BookPK() {
}
public BookPK(int id) {
this.id = id;
}
public int hashCode() {
return 0;
}
/**
* Return boolean is this instance
* of UserPK equals to
4.5 Описание процесса развертывания.Нам необходимо описать (например для стандартной реализации j2ee v. 1.2.1 компании Sun Microsystems): а) Транзактные свойства бизнес-методов каждого бина; б) Взаимосвязи между бинами для взаимных вызовов; в) Описание ссылок на ресурсы сервера приложений (например, это пулл соединений с СУБД); г) Специфические свойства бинов (Stateless Session EJB, Bean Managed Persistence Entity EJB, Primary Key Class для Entity EJB). После чего остается запустить сервер приложений, СУБД, Deployment Tool, в которой корректно и скрупулезно прописаны вышеуказанные параметры и произвести процедуру развертывания enterprise-приложения на сервер. И нет предела совершенству! 5. Ресурсы: |
| Справка | Условия | |
| В начало | Логин | Комментарий к колонке | Поиск | Почта |