Что такое EJB (Enterprise JavaBeans) и для чего она нужна? Можно ли обойтись без EJB при разработке WEB-приложений? Что даёт EJB программистам?
В java WEB-приложении можно использовать JSP (JavaServer Pages), JavaServer Faces (JSF), Struts, GWT. Для работы с базой данных можно использовать JDBC (Java Database Connectivity) или JPA (JBoss Hibernate). Применение в WEB-приложении servlet’a позволяет перехватить обращение к серверу и выполнить определенные действия, т.е. выполнить фильтрацию сообщений. Где и как в WEB-приложении можно использовать EJB?
Опыт показывает, что типовые задачи имеют типовые решения. Это и обеспечивает EJB, который представляет набор «фиксированных» решений типовых проблем, возникающих при разработке серверных приложений, а также проверенная временем схема реализации серверных компонентов. Эти фиксированные решения, или службы, предоставляются «контейнером EJB». Для доступа к этим службам необходимо создать специализированные компоненты, используя декларативные и программные EJB API, и развернуть их на сервере приложений.
Сервер приложений Java EE (Enterprise Edition) включает два основных компонента : WEB-container (для использования JSP, JSF, Struts и т.д.) и EJB-container. Первый компонент используется для создания пользовательского интерфейса и слабо подходит для описания бизнес-логики WEB-приложения. Для этого используется EJB-container.
Enterprise JavaBeans имеет спецификацию написания и поддержки серверных компонентов, содержащих бизнес-логику. Данная технология применяется, как правило, в том случае, если бизнес-логика требует один или несколько следующих сервисов :
- сервис распределённых транзакций;
- сервис сохранности данных (persistence);
- сервис управления данными;
- сервис событий;
- сервис именования и каталогов (JNDI);
- сервис безопасности и ограничения доступа к данным.
Технологию EJB можно рассматривать в двух аспектах: фреймворк и компонент. С точки зрения фреймворка EJB — это технология, предоставляющая для серверной части WEB-приложения множество готовых решений (управление транзакциями, безопасность, хранение информации и т.п.). С точки зрения компонента EJB — это надстройка над POJO-классом, описываемая с помощью аннотаций.
Содержание
Основные типы компонентов EJB
В языке EJB под компонентом подразумевается зерно (Bean), а под Enterprise подразумевают «корпоративный». EJB делит компоненты (зерна) на несколько типов, исходя из их предназначения :
- сессионные (Session Beans), которые могут быть
- stateful — с сохранением текущего состояния;
- stateless — без сохранения состояния;
- singleton — один объект для всех приложений (начиная с EJB версии 3.1).
Сессионный компонент Session Beans, иначе называемый сеансовый, вызывается клиентом (браузером) для выполнения вполне определенных операций, таких как, к примеру, проверка кредитной истории клиента. Слово «сессионный» предполагает, что экземпляр компонента доступен только на время выполнения определенной задачи сервером, и безвозвратно уничтожается в случае аварии или остановки сервера. Для доступа к серверной части приложения, клиент вызывает методы сессионного компонента, выполняющего определенные бизнес-задачи внутри сервера.
Сеансовый компонент с сохранением состояния EJB stateful автоматически сохраняет свое состояние между обращениями к нему от одного и того же клиента, и завершает свое существование либо по таймауту, либо по явному запросу клиента. Типичным примером компонента с сохранением состояния является корзина с покупками в интернет-магазине.
Сеансовые компоненты без сохранения состояния EJB stateless не хранят никакой информации о своем состоянии и являются прикладными службами, которые выполняют все необходимые действия в рамках запроса. EJB stateless можно использовать для реализации таких операций, как перевод средств на кредитную карту или проверку кредитной истории клиента. На основе stateless-бинов проектируются WEB-сервисы.
Компоненты-одиночки EJB singleton используются совместно всеми клиентами, имеющими к ним доступ, и продолжают свое существование на протяжении всего времени работы приложения. Информацию о своем состоянии EJB singleton сохраняет. Компонент-одиночку можно использовать, к примеру, в интернет-магазине для реализации скидки, поскольку правила предоставления скидки фиксированы и распространяются на всех клиентов.
Сеансовые компоненты могут вызываться локально или удаленно, посредством Java RMI. Компоненты-одиночки и компоненты без сохранения состояния могут также экспортироваться в виде веб-служб SOAP (Simple Object Access Protocol) или REST (Representational State Transfer).
Компоненты управляемые сообщениями MDB (Message-Driven Bean) подобно сеансовым компонентам реализуют некоторую прикладную логику и имеют одно важное отличие: клиенты никогда не вызывают методы MDB напрямую. Вместо этого компоненты MDB вызываются для обработки отправленных на сервер сообщений, что позволяет организовать асинхронный обмен сообщениями между частями системы. Типичными примерами подобных серверов сообщений могут служить IBM WebSphere MQ, Oracle Advanced Queueing и TIBCO. Компоненты MDB, как правило, применяются для повышения надежности интеграции систем и асинхронной обработки данных. Примером MDB сообщения может быть запрос на доставку товарных запасов от автоматизированной системы розничной торговли к системе управления поставками.
Entity Bean и Java Persistence API
EJB тесно связан с двумя спецификациями : с JPA, которая является стандартом хранения данных для Java EE и с CDI (Contexts and Dependency Injection) которая обеспечивает возможность внедрения зависимостей и предоставляет службы управления контекстом для всех компонентов Java EE, включая EJB.
Возможность автоматического сохранения объектов в реляционной БД с использованием технологии объектно-реляционного маппинга (ORM) — так называемый механизм работы с persistence объектами, является одним из главных достоинств EJB. В контексте EJB persistence провайдер — это ORM-фреймворк, который поддерживает JPA, определяющий стандарт для :
- конфигурации маппинга Entity Bean и его отображения в БД;
- EntityManager API — стандартный API для CRUD (Create, Read, Update, Delete) операций над сущностями;
- Java Persistence Query Language (JPQL) — для поиска и получения данных приложения.
EntityManager API — это интерфейс, который связывает класс сущности приложения (Entity Bean) и её представления в БД. EntityManager знает как нужно добавлять сущности в БД, обновлять и удалять их, а также предоставляет механизмы для настройки производительности, кэширования, транзакций и т.д. Для этого используется язык запросов JPQL, очень похожий на SQL.
Контейнеры EJB-container
Java-приложениям для работы нужна виртуальная машина JVM (Java Virtual Machine). Сеансовым компонентам и компонентам MDB для работы точно также необходим контейнер EJB. Можно считать EJB-container развитием базовой идеи JVM. Так же, как JVM прозрачно управляет памятью, EJB-container обеспечивает компоненты EJB такими службами, как обработка транзакций, поддержка безопасности, удаленные взаимодействия и веб-службы.
Согласно спецификации EJB3 контейнер предоставляет службы, применимые только к сеансовым компонентам и MDB. Операция добавления компонента EJB3 в контейнер называется развертыванием (deployment). После того, как EJB-компонент благополучно развернут в контейнере, он готов к использованию приложениями.
В Java технологиях контейнеры не ограничены только EJB3. Контейнер Java EE – это сервер приложений с поддержкой EJB3, веб-контейнеров (сервлеты, JSP, JSF, Struts, GWT) и других Java EE API и служб. Примерами реализаций контейнеров Java EE могут служить следующие серверы приложений : Oracle WebLogic, GlassFish, IBM WebSphere, JBoss и Caucho Resin.
Определение наименования компонентов EJB
Формат именования компонентов EJB имеет следующий вид :
- workspace — пространство имен;
- app-name — наименование приложения;
- module-name — наименование модуля;
- ejb-name — наименование компонента;
- object-name — полное наименование объекта.
В представленном формате именования компонентов EJB ряд элементов (workspace, module-name, ejb-name) присутствуют в имени всегда и являются обязательными. А элементы [app-name] и [!object-name] могут отсутствовать и считаются необязательными.
workspace
Сервер Java EE может включать четыре пространства имен workspace, каждое из которых представляет свою область видимости.
| java:comp | Область видимости компонента. Все компоненты EJB из WAR-файла попадают в одно общее пространство имен java:comp. Скорее всего Вам редко придется пользоваться этим пространством имен, поскольку основное его предназначение – сохранение обратной совместимости с версиями Java EE 6 и ниже, где java:comp было единственным стандартным пространством имен. |
| java:module | Область видимости модуля. Все компоненты модуля попадут в одно пространство имен java:module. Для обратной совместимости java:comp и java:module интерпретируются в веб-модулях как одно пространство имен. Когда это возможно, вместо java:comp следует использовать java:module. |
| java:app | Область видимости приложения. Компоненты из всех модулей одного приложения размещаются в общем пространстве имен java:app. Примером приложения может служить архив EAR. Все WAR- и EJB-компоненты, развертываемые из EAR-архива попадают в это пространство имен. |
| java:global | Глобальное пространство имен. В java:global размещаются все компоненты из всех модулей и всех приложений. |
app-name
Значение наименования приложения [app-name] не является обязательным и присутствует только в именах тех компонентов EJB, которые развертываются на сервере приложений из EAR-архива. Если архив EAR не использовался, тогда [app-name] отсутствует в переносимых именах JNDI компонентов EJB. По умолчанию в качестве значения [app-name] выбирается имя EAR-файла без расширения .ear. Переопределить это умолчание можно в файле application.xml.
module-name
Значение module-name всегда присутствует в наименовании ресурса и является обязательным. Оно зависит от того, как развертываются модули, содержащие компоненты EJB. Если компоненты развертываются из отдельных файлов EJB-JAR (JAR-файлы развертываются непосредственно), в качестве значения module-name выбирается имя EJB-JAR файла без расширения .jar. Это умолчание можно переопределить с помощью элемента module-name в конфигурационном файле META-INF/ejb-jar.xml.
Если развертываются компоненты, являющиеся частью веб-модуля (WAR-файл), по умолчанию в качестве значения module-name выбирается имя WAR-файла без расширения .war. Это умолчание можно переопределить с помощью элемента module-name в конфигурационном файле WEB-INF/web.xml. Если развертываются компоненты, являющиеся частью приложения (EAR-файл), по умолчанию значение module-name определяется в зависимости от того, являются ли компоненты EJB частью EJB-JAR или WAR в EAR. При развертывании компонентов из WAR-файла, выбор значения module-name выполняется в соответствии с правилом для WEB-модулей, которое можно переопределить в дескрипторе WEB-INF/web.xml. При развертывании компонентов из файлов EJB-JAR, значением module-name становится полный путь к каталогу, где находится файл EJB-JAR внутри EAR, плюс имя файла EJB-JAR без расширения .jar, которое можно переопределить в файле META-INF/ejb-jar.xml.
ejb-name
Значение наименования компонента ejb-name является обязательным и всегда присутствует в наименовании ресурса. Для компонентов EJB, помеченных аннотациями @Stateless, @Stateful или @Singleton, в качестве значения ejb-name по умолчанию выбирается имя класса компонента. Это значение можно переопределить с помощью атрибута name() аннотации. Для компонентов EJB, объявленных в файле ejb-jar.xml, значение ejb-name определяется с помощью элемента bean-name.
object-name
Значение полного наименования объекта [!object-name] является обязательным, и переносимые имена компонентов EJB с этим элементом всегда будут присутствовать в JNDI. Но сервер EE также требует, чтобы в JNDI присутствовало имя без этого значения. Такое «усеченное» наименование может пригодиться, когда доступ к компоненту осуществляется через единственный интерфейс (или если компонент вообще не имеет интерфейса).
Enterprise JavaBeans (также часто употребляется в виде аббревиатуры EJB) — спецификация технологии написания и поддержки серверных компонентов, содержащих бизнес-логику. Является частью Java EE.
Эта технология обычно применяется, когда бизнес-логика требует как минимум один из следующих сервисов, а часто все из них:
- поддержка сохранности данных (persistence); данные должны быть в сохранности даже после остановки программы, чаще всего достигается с помощью использования базы данных
- поддержка распределённых транзакций
- поддержка параллельного изменения данных и многопоточность
- поддержка событий
- поддержка именования и каталогов (JNDI)
- безопасность и ограничение доступа к данным
- поддержка автоматизированной установки на сервер приложений
- удалённый доступ
Каждый EJB-компонент является набором Java-классов со строго регламентированными правилами именования методов (верно для EJB 2.0, в EJB 3.0 за счет использования аннотаций выбор имён свободный). Бывают трёх основных типов:
- объектные (Entity Bean) — перенесены в спецификацию Java Persistence API
- сессионные (Session Beans), которые бывают
- stateless (без состояния)
- stateful (с поддержкой текущего состояния сессии)
- singleton (один объект на все приложение; начиная с версии 3.1)
10 октября 2011 г.
Основы EJB: часть 1
Сервер приложений j2ee состоит из двух основных элементов: контейнер web-приложения (JSP, JSF и т.д.) и EJB-контейнер. Первый служит для создания пользовательского интерфейса и слабо подходит для описания бизнес-логики приложения. Для этого используется вторая часть J2EE — EJB.
Технологию EJB (Enterprise Java Beans) можно рассматривать с двух точек зрения: как фреймворк, и как компонент.
С точки зрения компонента EJB — это всего-лишь надстройка над POJO-классом, описываемая с помощью аннотации. Существует три типа компонентов EJB:
- session beans — используется для описания бизнесс-логики приложения
- message-driven beans — так же используется для бизнесс-логики
- entities — используется для хранения данных
С точки зрения фреймворка EJB — это технология, предоставляющая множество готовых решений (управление транзакциями, безопасность, хранение информации и т.п.) для вашего приложения.
Перед тем, как продолжить обзор основ EJB остановимся на основе любого приложения — архитектуре.
Основные архитектуры EJB
Существует 2 основные архитектуры при разработке enterprise-приложений:
- традиционная слоистая архитектура (traditional layered architecture)
- domain-driven design (DDD)
Обе эти архитектуры предпологают разделение приложения на функциональные слои, каждый из которых используется для решения задач определенного плана.
К примеру, традиционная слоситая архитектура предпологает разделение приложения на 4 базовых слоя: слой презентации, слой бизнесс-логики, слой хранения данных и непосредственно слой самой базы данных.
Обычно слой презентации реализуется через web-приложение (т.е. используя JSP, JSF, GWT и т.п.) или web-сервис (что дает возможность написания клиента, к примеру, на C#). В нем реализовано взаимодействие с пользователем: формы для получения запросов от пользователя и средства для предоставления ему запрошеной информации. Слой бизнесс-логики является основой для enterprise-приложения. В нем описываются бизнесс-процессы, производится поиск, авторизация и множество других вещей. Слой бизнесс-логики использует механизмы слоя хранения данных. Чем отличается слой хранения данных и слой базы данных? Тем, что в первом описываются высокоуровневые объектно-ориентированные механизмы для работы с сущностями БД, в то время как второй — это и есть непосредственно база данных (Oracle, MySQL и т.п.)
Архитектура DDD предпологает, что объекты обладают бизнесс-логикой, а не являются простой репликацией объектов БД. Многие программисты не любят наделять объекты логикой и создают отдельный слой, называемый service layer или application layer. Он похож на слой бизнесс-логики традиционной слоистой архитектуры за тем лишь отличием, что он намного тоньще.
Типы компонентов EJB
Как уже было сказано выше существует 3 типа компонентов EJB: session beans, message-driven beans и entities.
Рассмотрим каждый из этих компонент немного детальнее.
Session beans
Вызываются пользователем для совершения какой-либо бизнесс-операции. Существует 2 типа session-beans: stateless и stateful.
Stateful-бины автоматически сохраняют свое состояние между разными клиентскими вызовами. Типичным примером stateful-бина является корзина в интернет-магазине.
Stateless-бины используются для реализации бизнесс-процессов, которые могут быть завершены за одну операцию.Так же на основе stateless-бинов проектируются web-сервиса.
Message-driven beans
Так же как и session beans используются для бизнесс-логики. Отличие в том, что клиенты никогда не вызывают MDB напрямую. Обычно сервер использует MDB в асинхронных запросах.
Entities и Java Persistence API
Одним из главным достоинством EJB3 стал новый механизм работы с persistence — возможность автоматически сохранять объекты в реляционной БД используя технологию объектно-реляционного маппинга (ORM).
В контексте EJB3 persistence провайдер — это ORM-фреймворк, который поддерживает EJB3 Java Persistence API (JPA). JPA определяет стандарт для:
- конфигурации маппинга сущностей приложения и их отображения в таблицах БД;
- EntityManager API — стандартный API для CRUD (create, read, update, delete) операций над сущностями;
- Java Persistence Query Language (JPQL) — для поиска и получения данных приложения;
Можно сказать, что session beans — это "глаголы" приложения, в то время как entities — это "существительные".
EntityManager — это инерфейс, который связывает класс сущности приложения и его представление в БД. EntityManager знает как нужно добавлять сущности в базу, одновлять их, удалять, а так предоставляет механизмы для настройки производительности, кэширования, транзакций и т.д.
JPQL — это похожий на SQL язык запросов.
Реализация
Теперь рассмотрим реализацию этих сущностей. В EJB3 мы используем POJO (Plain Old Java Objects), POJI (Plain Old Java Interfaces) и аннотации. Если с первыми двумя всё понятно, то про аннотации стоить поговорить отдельно. Аннотация записывается так:
Методы жизненного цикла EJB
У stateless и MDB бинов существует 2 события жизненного цикла, которые мы можем перехватить: создание и удаление бина. Метод, который будет вызываться сразу после создании бина помечается аннотацией javax.annotation.PostConstruct, а перед его удалением — javax.annotation.PreDestroy. Stateful бины обладают помимо рассмотреных выше еще 2 событиями: при активации (javax.ejb.PostActivate) и при деактивации (javax.ejb.PrePassivate).
Особенности stateless и stateful бинов
Один bean может содержать множество клиентских методов. Этот момент является важным для производительности, так как контейнер помещает экземпляры stateless-бинов в общее хранилище и множество клиентов могут использовать один экземпляр бина.
В отличии от stateless stateful бины инстанцируются для каждого пользователя отдельно.
Еще пара слов об интерфейсах
Интерфейс может быть помечен как Local, что сделает классы, реализующие этот интерфейс, классами локальной бизнесс-логики. Локальные интерфейсы не требуют никаких дополнительные действий при реализации.
В противном случае интерфейс может быть помечен как Remote, что обеспечит возможность работы RMI. Обычно такой интерфейс расширяет интерфейс Remote, но это не обязательно.
Если вас интересует функциональность и Local и Remote интерфейсов — вот интересный пример из "EJB 3 in Action":
Перехватчики
При создании enterprise-приложений часто возникает необходимость записывать лог вызываемых методов (в целях отладки или для лога безопасности), а так же контролировать доступ пользователей к отдельным частям приложения. Для этого используются перехватчики — объекты, методы которых вызываются автоматически при вызове метода EJB-бина. Объект-перехватчик является POJO, за тем лишь исключением, что метод, который должен вызываться автоматически аннотируется @AroundInvoke, например:
Обратите внимание на возвращаемое значение и параметр функции. В данном случае мы говорим контейнеру, что после вызова перехватчика можно вызывать метод, который он перехватил (или следующий за ним перехватчик), однако мы могли сгенерировать исключение или не вызывать метод proceed() и тогда метод EJB-бина не выполнился бы.
Использовать перехватчики можно двумя путями: указать его применение через аннтоации для каждого класса или метода в отдельности или указать перехватчик по-умолчанию для определенных (или всех) бинов.
Чтобы перехватчик применился только к определенному методу перех декларацией метода можно написать аннотацию @Interceptors( MyLogger.class ). Чтобы перехватчик работал для всех методов бина эту же аннотацию можно было бы написать перед декларацией класса, например:
Можно указывать несколько перехватчиков, тогда их перечисляют через запятую, например:
Порядок вызова перехватчиков никак нельзя задать через аннотации, но его можно изменять, если описывать их через дескриптор развертывания.
Один перехватчик описывается так:
Сначала вызывается перехватчик по-умолчанию, потом специфичный для класса, а за ним для метода. Если вы не хотите чтобы для вашего метода вызывался перехватчик по-умолчанию — используйте аннотацию @ExcludeDefaultInterceptors или @ExcludeClassInterceptors.





