СТАТЬЯ
04.06.02

Предыдущая часть

Методология построения корпоративных информационных систем на основе технологии EJB
(Часть 5–8)

© Евгений Игумнов
Опубликовано на сайте http://ejbcorba.euro.ru

Дерево имен JNDI

JNDI (Java Naming Directory Interface). Расскажу немного подробнее об этом сервисе. Приведу хорошую аналогию. Мы постоянно пользуемся службой DNS не задумываясь как она работает и почему она появилась. Для тех кто плохо ориентируется в DNS я сейчас поясню основную идею. Как уже всем известно каждый компьютер подключенный к сети Internet имеет свой уникальный IP адрес. Например 213.10.2.4 или 194.145.90.158. Запоминать такие адреса человеку чаще всего сложно. И придумали сопоставлять каждому IP адресу определенное составное имя. Например kooper.favour.com или beta.alpha.rest.com. Такие имена значительно проще запомнить человеку. К тому же читая имя справа налево человек может видеть иерархию имен, т.е. есть сервер com к нему подключен сервер favour, а к favour подключен kooper. Конечно такая иерархи чаще всего условная и не имеет никакого отношения к реальному положению дел, но этот механизм позволяет примерно понять какой фирме принадлежит компьютер с таким именем. Побочным эффектом такого подхода стала очень интересная и удобная вещь. Так как теперь все используют имена в место конкретных IP адресов, в случае смены IP адреса не нужно оповещать всех об этом. Нужно только поменять соответствие между именем и IP адресом. Вы это бы хорошо оценили если бы у Вас был бы популярный Web-портал и в один прекрасный момент порталу перестало бы хватать пропускной способности канала провайдера и вам срочно нужно сменить старого интернет провайдера на нового и не хотелось бы терять посетителей которые помнят Ваш IP адрес, т.к. новый провайдер выдаст вам новый IP адрес. А тут все просто. Смени у имени в DNS старый IP адрес на новый. И пользователи Вашего портала ничего не заметят.

А теперь вернемся к службе JNDI. Каждому компоненту EJB сопоставляется имя, которое публикуется на дереве имен JNDI. И клиентское приложение обращается к этой службе зная имя под которым зарегистрирован EJB компонент. Обратившись к службе имен клиентское приложение получает по имени объектную ссылку. На самом деле существует менее изящный способ получения объектной ссылки. Но для начала я думаю необходимо пояснить, что такое объектная ссылка. Так как изначально полагается что компоненты работают в разных адресных пространствах с клиентским приложением, т.е. в разных виртуальных машинах и все их взаимодействие является сетевым, то не совсем понятно что такое объектная ссылка в этом случае. Классически объектная ссылка это можно сказать адрес в памяти, но в случае удаленного взаимодействия это адрес хоста, номер порта, плюс много всякой служебной информации и плюс еще к тому что эта объектная ссылка уникальная и ее значение не возможно предсказать. Самым первый способ получения объектной ссылки выглядит так: запускается компонент на стороне сервера и полученная объектная ссылка записывается в файл и передается на сторону клиента. Можно ее перенести на дискете или передать по FTP или получить с web сервера по http. Не очень красивое решение. Сервис именования JNDI позволяет по имени получить объектную ссылку компонента. Сценарий запуска сервера и взаимодействия клиента уже выглядит следующим образом: запускается компонент на стороне сервера, который себя регистрирует на дереве имен JNDI под заранее оговоренным с клиентом именем, а потом клиентское приложение через сервис JNDI по имени получает объектную ссылку на этот компонент.

Еще одним преимуществом использования сервиса JNDI проявляется в следующей ситуации. Предположим Вы разработали 6 компонентов EJB, эти компоненты общаются с друг другом для выполнения запросов поступающих со стороны клиентского приложения. И вот настал тот долгожданный день, когда Ваш сервер приложений перестал справляться с вычислительной нагрузкой. И вот Вы решили компоненты EJB разместить на 3 серверах предложений. Переход от одного сервера приложений к трем изображен на рис. 11.

Рис. 11

Как видно из рисунка, все компоненты EJB зарегистрированы на сервисе JNDI и при взаимодействии сначала ищут друг друга на JNDI. В случае когда их разместили на разных серверах приложений, компоненты даже ничего не заметили так как доступ к соседним компонентам получали через сервис JNDI. И естественно клиентское приложение, тоже ничего не почувствовало. Что же мы получаем в итоге? Мы распределили наши компоненты на разные вычислительные машины и при этом не изменили ни одной строчки кода ни в клиентском приложении ни в самих компонентах.

Сессионные бины

Сессионный бин по функциональности очень похож на обычный класс, от которого вы можете порождать объекты и использовать. Отличительной чертой является способ создания объекта. Как уже говорилось выше существуют Home-интерфейс, который является точкой входа в ваш бин. В нем вы определяете метод create, через который можно создавать сессионные бины на стороне сервера. Вообще сессионные бины предназначены быть представителем клиента на стороне сервера или быть его функциональным расширением, другими словами они нужны в течении сессии работы клиента, а потом их уничтожают. Сессионный бин показан на рис. 12.

Рис. 12

Вы можете объявить бизнес методы бина в Remote-интерфейсе(Test) и реализовать их в Implementation бина (TestBean). Другими словами из клиента вы будете вызывать методы Remote-интерфейса, а контейнер будет передавать управлению на реализацию бина сопоставленную с вашим обращением. Есть такое понятие как исполнитель, который сопоставляется бину и обеспечивает его функциональные возможности. Это понятие было введено, так как бин является больше абстракцией, которую нужно поддерживать реализацией. Контейнер управляет пулом исполнителей бинов и решает, какому из исполнителей передать управления. Таким образом, обеспечивается равномерное распределение нагрузки между исполнителями.

Сессионные бины бывают двух видов: Stateless and Stateful. Другими словами бины могут не помнить свое состояние и помнить.

Сессионный бин не помнящий свое состояние

Бывает ситуации, когда Вам не нужно, что бы бин помнил свое состояния между двумя вызовами методов, т.е. вы не складываете информацию в бин методами set и в последующем не пытаетесь ее запросить методами get. Указав, что ваш бин является Stateless вы даете возможность контейнеру лучше использовать ресурсы вычислительной машины при обработки запросов к такой разновидности сессионного бинов.

Сессионный бин помнящий свое состояние

Бывает ситуации, когда Вам нужно, что бы бин помнил свое состояния между двумя вызовами методов, т.е. вы складываете информацию в бин методами set и в последующем пытаетесь ее запросить методами get. Указав, что ваш бин является Stateful вы обязываете контейнер производить сериализацию на исполнителе, когда серверу не хватает ресурсов для обработки запросов пользователей и контейнер решает сопоставить не занятого исполнителя с запросом пользователя, то ему необходимо сначала сериализировать его состояние. А если попроще, то давайте представим две центрифуги. В каждой из них лежит грязное белье пользователя. Две центрифуги и два пользователя. Предположим что оба пользователя включили режим стирки. Стирка закончилась в первой центрифуге. Первый пользователь пока еще размышляет включить ему режим отжима или так свое белье забрать. В этот момент приходит третий пользователь, а центрифуги всего две. Подходит владелец прачечной и вытаскивает не отжатое белье первого пользователя и помещает белье третьего и запускает центрифугу. После стирки белья третьего пользователя, отжимается белье второго, а потом и третьего пользователя. Выходит что центрифуги две, а пользователя три. Для того, что бы это работало нужно доставать и обратно класть белье, этот процесс называется сериализацией. Или говоря научным языком в случае, когда исполнителей не хватает, то контейнер просто сериализирует состояние одного из исполнителей, передает управление на него, а когда настоящий владелец сериализированного исполнителя пытается на нем вызвать бизнес метод, контейнер производит сериализацию состояния другого исполнителя и восстанавливает состояние сериализированного бина. Сериализация состояния бина происходит обычно на винчестер.

Жизненный цикл сессионных бинов

Разберем жизненный цикл Stateless сессионного бина. Жизненный цикл изображен на рис. 13.

Рис. 13

Жизненный цикл сессионного бина не помнящего своего состояния довольно прост. Всего два возможных состояния это когда еще ejbObject не существует и когда он создан и помещен в пул. Контейнер не ставит строго соответствия между конкретным клиентом который вызывает бизнес метод и конкретным исполнителем. Обычно для обработки бизнес метода берется тот исполнитель, который "не занят".

Разберем жизненный цикл в Stateful сессионного бина. Жизненный цикл изображен на рис. 14.

Рис. 14

Жизненный цикл сессионного бина помнящего своего состояния несколько посложнее. В принципе он похож на предыдущей, только с одним расширением, т.к. необходимо строго сопоставлять клиента с его сессионным бином вводится понятие активизации и пассивизации бина. Во время сопоставления клиента с его сессионным бином необходимо провести активацию, т.е. реализуя метод ejbActivate вы можете в нем определить открытия например сетевых соединений, которые использует бин и когда контейнер решает воспользоваться этим бином что бы обслужить другого пользователя, то происходит сначала пассивизация, которую вы можете реализовать в методе ejbPassivate например закрытия тех соединений которые вы открыли, а потом и активация соответственно. Метод ejbActivate вызывается сразу после сериализации, а метода ejbPassivate до сериализации.

Транзакции в сессионных бинах

Как не странно это звучит, сессионные бины могут участвовать в транзакциях. Есть такое понятие, как транзактивный контекст. Другими словами бизнес методы сессионного бина могут выполнятся в транзактивном контексте. Это значит, что если вы начнете транзакцию и вызовите метод какого-либо сессионного бина, то бин на котором будет вызван этот метод будет вовлечен в транзакцию и будет в текущем (вашем) транзактивном контексте. Если вы решите зафиксировать (commit) свои действия, то координатор транзакций использует ваш транзактивный контекст для этих целей что бы узнать какие бины участвовали в транзакции и сообщить им о завершении транзакции. С другой стороны сессионый бин может обратиться к сессионному контексту что бы узнать участвует он в транзакции или нет. Также во время выполнения бизнес метода, бин может решить что выполнение происходит с ошибкой и сказать транзактивному контексту что бы был произведен откат (rollback) транзакции.

Выше я описал случай когда транзакции управляются самим бином. Но есть второй режим когда транзакцией управляет сам контейнер и естественно теряется гибкость. Не буду тут пояснять второй случай что бы не запутать читателя. Второй случай будет объяснен далее.

Сущностный бин

Идея заложенная в сущностные бины следующая. Нам приходится хранить информацию в реляционных таблицах и обеспечить к ним гибкий доступ используя ООП. Есть реляционная таблица на нее нужно создать сущностный бин. Реализация сущностного бина соответствует строчки в базе данных. Сессионный бин изображен на рис. 15.

Рис. 15

Покажу точки соприкосновения ООП с SQL-запросами. В ejbCreate происходит INSERT, в ejbRemove - DELETE, в ejbStore - UPDATE, в ejbLoad - SELECT. На рисунке показан пример бина, который обслуживает таблицу всего с двумя столбцами PK и title. Также присутствуют поисковые методы ejbFind, которые позволяют выдергивать идентификаторы объектов из базы данных, но не отвечают за загрузку их состояний в память. Кстати, процесс перехода из строчки таблицы в объект называется материализацией, а сохранения объекта в строчку таблицы - дематериализацией. Механизм взаимодействия с сущностными бинами такой же как с сессионными, за исключением того, что на HOME-интерфейсе появляются Find-методы, которые не создают объекты в базе данных, а находят что бы с ними можно было работать. Архитектура сущностного бина отличается понятием основной ключ Primary Key, который представлен в нашем примере как класс EntityPK. Этот класс обворачивает основной ключ таблицы, которую обслуживает бин.

Источник данных DataSource

В реализации сущностного бина необходим, что бы посылать SQL-запросы использовать соединение с БД. Был придумал пул соединения с БД (DataSource). Это было сделано что бы не тратить ресурсы и время на создания новых соединений с БД. Создаются соединения через DataSource и когда бин перестает его использовать, соединения не закрывают а держат в пуле и когда другой бин просит соединение то ему отдают давно уже созданное соединение. На самом деле процесс несколько сложнее из-за транзакций, но идея изложенная выше верна.

Механизм сохранения управляемый бином

Можно самому в реализации бина прописать все взаимодействия с БД. Такой подход называется механизмом сохранения управляемый бином (Bean-Managed Persistence). Лично я считаю, что таким образом можно добиться более эффективных и гибких решений. Особенно Вы это начнете понимать когда вам в ТЗ напишут что бы бины были совместимы с 4-мя типами СУБД.

Механизм сохранения управляемый контейнером

Используя этот механизм, программист описывает в дескрипторе описания бина имя таблицы и типы ее столбцов. После этого добавляет get/set методы в реализацию бина, а механизмом синхронизации бина с БД управляет уже сам контейнер. Таким образом время разработки бина сокращается в несколько раз. Такой механизм называется Container-Managed Persistence.

Атрибут транзактивности бина

Атрибуты транзактивности бина нужны только в том случае если транзакции управляются самим бином. Бывают следующие транзактивные атрибуты Required, RequiresNew, Mandatory, NotSupported, Supports, Never. Один из этих атрибутов вы указываете в XML описании вашего бина на каждый ваш бизнес метод или на все методы сразу. На сама деле этот атрибут говорит контейнеру, что делать с транзактивным контекстом в случае вызова бизнес метода на бине. Например: если был вызван метод не в транзакции, то начать новую транзакцию или если если вызван в транзактивном контексте, то создать свою транзакцию и выполнять метод в ней. И таких вариаций много. Для полного описания обратитесь к спецификации или к документации компании у который вы купили сервер приложений.

Четыре уровня изоляции транзакции

Обычно технологию EJB применяют для систем, к которым предъявлены высокие требования. И волей-неволей Вам придется столкнутся с проблемой изоляции транзакций.

TRANSACTION_READ_UNCOMMITED

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

TRANSACTION_READ_COMMITED

Этот уровень Вас избавит от грязного чтения.

TRANSACTION_REPEATABLE_READ

Этот уровень вас избавит от проблемы неповторимого чтения. Это возникает тогда, когда вы во время транзакции считали какую-то строчку, а через некоторое время считали ее еще раз в той же транзакции и обнаружили, что она была изменена в другой транзакции. С таким уровнем изоляции вы избавитесь от этой проблемы. Просто, что вы будете считывать в одной транзакции будет блокировано на измненние в другой пока вы не закончите первую.

TRANSACTION_SERIALIZABLE

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

Жизненный цикл сущностных бинов

Жизненный цикл (ЖЦ) сущностных бинов похож на сессионный, но несколько сложнее. Жизненный цикл изображен на рис. 16.


Рис. 16

Скажу честно, что бы вы поняли, как это работает вам потребуется очень хорошо изучить архитектуру EJB, так что я в свое статье коснусь только основной мысли. В ЖЦ сущностного бина добавились два события это вызов методов ejbLoad и ejbStore, которые синхронизируют состояние бина с состоянием БД. Метод ejbLoad вызывается, когда бин попадает в транзакцию, а ejbStore когда транзакция завершается.

Дополнительную информацию Вы можете получить в компании Interface Ltd.

Обсудить на форуме Borland
Отправить ссылку на страницу по e-mail


Interface Ltd.
Тel/Fax: +7(095) 105-0049 (многоканальный)
Отправить E-Mail
http://www.interface.ru
Ваши замечания и предложения отправляйте автору
По техническим вопросам обращайтесь к вебмастеру
Документ опубликован: 04.06.02