Опубликован: 18.03.2010 | Доступ: свободный | Студентов: 840 / 85 | Оценка: 4.48 / 4.33 | Длительность: 12:01:00
Лекция 4:

Технология Enterprise Java Beans. Часть 2

Аннотация: В данной лекции рассматривается важные составляющие технологии EJB - объектные компоненты и компоненты, управляемые сообщениями

Объектные компоненты

Как уже говорилось ранее, объектные компоненты моделируют прикладные понятия, которые могут быть описаны существительными. Это не закон установленный раз и навсегда, скорее эмпирическое правило, которое позволяет определять, когда прикладное понятие следует реализовать как объектный компонент, а когда - как сеансовый или вообще управляемый состоянием компонент. Объектные компоненты описывают и состояние, и поведение объектов из жизни. Разработчики могут добавлять к объектным компонентам данные и правила, характеризующие компоненты.

Объектные компоненты представляют записи в базе данных. При изменении объектных компонентов происходят изменения в базе данных. В предыдущих примерах уже рассматривалась возможность внесения изменения в базу данных непосредственно через сеансовые компоненты, но это было не очень удобно - приходилось, к примеру, для создания заказа в базе данных выполнять несколько запросов SQL.При использовании объектных компонентов можно было бы просто использовать метод Order.createOrder (List commoditiesList). Компонент Order представляет приложению полный доступ к информации о заказах, а также возможность управлять ими -создавать, модифицировать и удалять. При помощи объектных компонентов разработку можно упростить и сделать более рентабельной.

Когда объектный компонент создается, в базу данных должна быть вставлена новая запись и создан экземпляр компонента, связанный с этими данными. По мере того, как компонент изменяется, его состояние меняется, и изменения должны быть синхронизированы с данными в базе данных. За процесс координации данных, представляющий экземпляр компонента, с базой данных, отвечает служба Persistence.

Существует два основных типа объектных компонентов, различающихся реализацией механизма постоянства: компоненты с постоянством, управляемым контейнером (container-managed persistence или CMP),и компоненты поддерживающие постоянство самостоятельно (bean-managedpersistence или BMP).

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

Начиная со спецификации EJB 2.0, CMP подверглось очень сильным изменениям. В результате CMP теперь больше не является обратно совместимым с предыдущими спецификациями. Поэтому довольно часто используют сокращение CMP 2.0.

В CMP 2.0 контейнер объектных компонентов автоматически управляет их состоянием. Контейнер заботится о регистрации компонентов в транзакциях и поддерживает их состояние в базе данных. Разработчик компонентов описывает атрибуты и связи компонентов при помощи виртуальных (virtual) полей постоянства и отношений. Разработчик не определяет их явно. Вместо этого в классе создаются абстрактные методы доступа ( set и get ).

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

При создании объектного компонента (BMP или CMP),контейнер EJB выполняет следующую последовательность действий:

  • Контейнер вызывает метод Class.newInstance() у класса объектного компонента. До этого момента объектный компонент существовал только как набор файлов (класса компонента, интерфейсов и дескриптора развертывания). У компонента вызывается метод setEntityContext (EntityContext). После этого созданный компонент помещается в пул объектных компонентов. Обычно контейнер хранит несколько экземпляров компонента в пуле. Они помещаются туда при запуске контейнера. В дальнейшем, в зависимости от оьстоятельств, контейнер может увеличивать или уменьшать количество экземпляров компонентов в пуле. Компонент, находящийся в пуле, способен выполнять запросы ejbFind<суффикс> и ejbSelect<суффикс> (рассмотрим далее).
  • При вызове методов ejbCreate() а затем метода ejbPostCreate() у домашнего интерфейса, или же когда контейнер активирует компонент посредством метода ejbActivate(), компонент переходит в состояние готовности. После завершения метода ejbCreate() создается первичный ключ - идентификатор созданного объекта, а затем уже вызывается метод ejbPostCreate(). В состоянии готовности компонент способен обслуживать запросы от клиента. Когда клиент вызывает метод удаленного интерфейса getName(), то этот метод вызывается посредством RMI у компонента на сервере. В состоянии готовности могут также вызываться методы ejbLoad() и ejbStore(). Они вызываются в любом порядке -порядок определяется производителем компонента. Некоторые производители вызывают эти методы перед каждым выполнением прикладного метода.
  • Компонент может переходить обратно из состояния готовности в пул в случае пассивизации (посредством метода ejbPassivate() ). Эта операция может выполняться для более эффективного управления ресурсами. Также компонент может переходить обратно при вызове метода ejbRemove() - в этом случае все данные о компоненте удаляются из базы данных.
  • Когда контейнер решит уменьшить количество экземпляров в пуле, он удаляет некоторые из них. Теперь сборщик мусора может их окончательно удалить из памяти. После удаления из пула, у компонента вызывается метод unsetEntityContext().

Пример "Космические корабли"

Компонент

Разработаем объектный компонент BMP. Он будет использоваться для хранения информации о космических кораблях. Параметры космических кораблей компонент будет получать из базы данных, посредством его set и get методов клиентская программа или другие компоненты смогут изменять эти параметры. Компонент будет называться WidgetBean.

Создание таблицы в базе данных
Инфологическая модель базы данных космических кораблей

Рис. 4.1. Инфологическая модель базы данных космических кораблей

Как показано на Рис. 4.1, база данных космических кораблей состоит из одной таблицы. В ней каждому кораблю дается текстовое описание и цена. ID последнего добавленного корабля также сохраняется в пакете, что делает его доступным для прикладного приложения.

create or replace package WIDGET_ID_PKG as LAST_ID integer;
function GET_LAST_ID return integer; end WIDGET_ID_PKG; 
/
create or replace package body WIDGET ID PKG as function GET_LAST_ID return integer is 
begin
return LAST_ID; 
end GET_LAST_ID;
end WIDGET_ID_PKG;

/

drop table WIDGETS;
create table WIDGETS   (
ID integer not null, 
DESCRIPTION varchar(50) not null, 
PRICE float not null, 
primary key(ID)
);
drop sequence WIDGETS_SEQ;
create sequence WIDGETS_SEQ 
start with 1 
increment by 1
nomaxvalue;

create trigger WIDGETS_TRIGGER before insert on WIDGETS 
for each row 
begin
select WIDGETS_SEQ.nextval into WIDGET_ID_PKG.LAST_ID from dual;
select WIDGET_ID_PKG.LAST_ID into  :new.id from dual;
end;
/
insert into WIDGETS(DESCRIPTION, PRICE)
values('Buran',   1000);
insert into WIDGETS(DESCRIPTION, PRICE)
values('Shuttle',   2000);
insert into WIDGETS(DESCRIPTION, PRICE)
values('Space Ship One',   3000);
Удаленный интерфейс

Вначале создадим для компонента удаленный интерфейс, который будет состоять только из get и set методов. Эти методы будут соответствовать полям в только что созданной таблице WIDGETS.

public interface WidgetRemote extends EJBObject  
{
public Integer getId()   throws RemoteException;
public double getPrice()   throws RemoteException;
public String getDescription()   throws RemoteException;
public void setPrice(double price)   throws RemoteException;
public void setDescription(String description)   throws RemoteException;
}

Стоит отметить, что для ID определен только get метод. ID - это первичный ключ, создаваемый базой данных, он должен быть уникальным. Если позволить прикладному приложению его изменять, то может нарушиться условие уникальности первичных ключей. К тому же практический смысл операции изменения этого первичного ключа невелик.

Домашний интерфейс

Домашний интерфейс компонента WidgetBean несколько отличается от аналогичных домашних интерфейсов сеансовых компонентов. В нем помимо create методов определены find методы, которые позволяют осуществлять поиск компонентов по определенным параметрам. К примеру, можно искать все космические корабли с ценою не выше заданной.

Для компонента WidgetBean определен create метод, который создает новый экземпляр компонента с заданным описанием и ценой. В качестве find методов определены два метода, которые обычно присутствуют у всех домашних интерфейсов объектных компонентов -

  • public Collection findAll() - возвращает коллекцию из всех компонентов, определенных на данный момент в базе данных. В качестве объектов коллекции выступают удаленные интерфейсы компонента.
  • public WidgetRemote findByPrimaryKey(Integer widgetId) -возвращает удаленный интерфейс компонента с заданным первичным ключом. В случае, если компонента с таким первичным ключом не существует, генерируется исключение javax.ejb.FinderException.
public interface WidgetHome extends EJBHome  
{
public WidgetRemote create(String description,  double price)
throws RemoteException,   CreateException;
public WidgetRemote findByPrimaryKey(Integer widgetId)
throws FinderException,   RemoteException;
public Collection findAll()   throws FinderException,   RemoteException;
}
Антон Зубеков
Антон Зубеков

Здравствуйте, подскажите пожалуйста где можно достать материалы по курсу Кросс-платформенные и многозвенные технологии, о которых говориться, к примеру, в Лекции 2. Пример "Служба мгновенных сообщений"