Сервер приложений j2ee состоит из двух основных элементов: контейнер web-приложения (JSP, JSF и т.д.) и EJB-контейнер. Первый служит для создания пользовательского интерфейса и слабо подходит для описания бизнес-логики приложения. Для этого используется вторая часть J2EE - EJB.
Технологию EJB (Enterprise Java Beans) можно рассматривать с двух точек зрения: как фреймворк, и как компонент.
С точки зрения компонента EJB - это всего-лишь надстройка над POJO-классом, описываемая с помощью аннотации. Существует три типа компонентов EJB:
Перед тем, как продолжить обзор основ EJB остановимся на основе любого приложения - архитектуре.
Основные архитектуры EJB
Существует 2 основные архитектуры при разработке enterprise-приложений:
К примеру, традиционная слоситая архитектура предпологает разделение приложения на 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 - это инерфейс, который связывает класс сущности приложения и его представление в БД. EntityManager знает как нужно добавлять сущности в базу, одновлять их, удалять, а так предоставляет механизмы для настройки производительности, кэширования, транзакций и т.д.
JPQL - это похожий на SQL язык запросов.
Реализация
Теперь рассмотрим реализацию этих сущностей. В EJB3 мы используем POJO (Plain Old Java Objects), POJI (Plain Old Java Interfaces) и аннотации. Если с первыми двумя всё понятно, то про аннотации стоить поговорить отдельно. Аннотация записывается так:
Какие аннотации могут быть?
В качестве session bean может выступать обычный класс Java удовлетворяющий следующим условиям:
Методы жизненного цикла EJBТехнологию EJB (Enterprise Java Beans) можно рассматривать с двух точек зрения: как фреймворк, и как компонент.
С точки зрения компонента EJB - это всего-лишь надстройка над POJO-классом, описываемая с помощью аннотации. Существует три типа компонентов EJB:
- session beans - используется для описания бизнесс-логики приложения
- message-driven beans - так же используется для бизнесс-логики
- entities - используется для хранения данных
Перед тем, как продолжить обзор основ 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) - для поиска и получения данных приложения;
EntityManager - это инерфейс, который связывает класс сущности приложения и его представление в БД. EntityManager знает как нужно добавлять сущности в базу, одновлять их, удалять, а так предоставляет механизмы для настройки производительности, кэширования, транзакций и т.д.
JPQL - это похожий на SQL язык запросов.
Реализация
Теперь рассмотрим реализацию этих сущностей. В EJB3 мы используем POJO (Plain Old Java Objects), POJI (Plain Old Java Interfaces) и аннотации. Если с первыми двумя всё понятно, то про аннотации стоить поговорить отдельно. Аннотация записывается так:
@<имя аннотации>(<список парамет-значение>)
Какие аннотации могут быть?
- Stateless - говорит контейнеру, что класс будет stateless session bean. Для него контейнер обеспечит безопасность потоков и менеджмент транзакций. Дополнительно, вы можете добавить другие свойства, например прозрачное управление безопасностью и перехватчики событий;
- Local - относится к интерфейсу и говорит, что bean реализующий интерфейс доступен локально
- Remote - относится к интерфейсу и говорит, что bean доступен через RMI (Remote Method Invocation)
- EJB - применятеся в коде, где мы используем bean.
- Stateful - говорит контейнеру, что класс будет stateful session bean.
- Remove - опциональная аннотация, которая используется с stateful бинами. Метод, помеченный как Remove говорит контейнеру, что после его исполнения нет больше смысла хранить bean, т.е. его состояние сбрасывается. Это бывает критично для производительности.
- Entity - говорит контейнеру, что класс будет сущностью БД
- Table(name="...") - указывает таблицу для маппинга
- Id, Column - параметры маппинга
- WebService - говорит, что интерфейс или класс будет представлять вэб-сервис.
- и много-много других...
В качестве session bean может выступать обычный класс Java удовлетворяющий следующим условиям:
- иметь как минимум один метод
- не должен быть абстрактным
- иметь конструктор по-умолчанию
- методы не должны начинаться с "ejb" (например ejbCreate, ejbDoSomething)
У 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":
public interface BidManager{ void addBid(Bid bid); List<Bid> getBids(Item item); } @Local public interface BidManagerLocal extends BidManager { void cancelBid(Bid bid); } @Remote public interface BidManagerRemote extends BidManagerLocal {} @WebService public interface BidManagerWS extends BidManager {}
Перехватчики
При создании enterprise-приложений часто возникает необходимость записывать лог вызываемых методов (в целях отладки или для лога безопасности), а так же контролировать доступ пользователей к отдельным частям приложения. Для этого используются перехватчики - объекты, методы которых вызываются автоматически при вызове метода EJB-бина. Объект-перехватчик является POJO, за тем лишь исключением, что метод, который должен вызываться автоматически аннотируется @AroundInvoke, например:
public class MyLogger { @AroundInvoke public Object logMethodEntry( InvocationContext invocationContext ) throws Exception { System.out.println("Entering methid: " + invocationContext.getMethod().getName() ); return invocationContext.proceed(); } }Обратите внимание на возвращаемое значение и параметр функции. В данном случае мы говорим контейнеру, что после вызова перехватчика можно вызывать метод, который он перехватил (или следующий за ним перехватчик), однако мы могли сгенерировать исключение или не вызывать метод proceed() и тогда метод EJB-бина не выполнился бы.
Использовать перехватчики можно двумя путями: указать его применение через аннтоации для каждого класса или метода в отдельности или указать перехватчик по-умолчанию для определенных (или всех) бинов.
Чтобы перехватчик применился только к определенному методу перех декларацией метода можно написать аннотацию @Interceptors( MyLogger.class ). Чтобы перехватчик работал для всех методов бина эту же аннотацию можно было бы написать перед декларацией класса, например:
@Interceptors( MyLogger.class ) @Stateless public class MyClass { ... }Можно указывать несколько перехватчиков, тогда их перечисляют через запятую, например:
@Interceptors( MyLogger1.class, MyLogger2.class )Порядок вызова перехватчиков никак нельзя задать через аннотации, но его можно изменять, если описывать их через дескриптор развертывания.
Один перехватчик описывается так:
Сначала вызывается перехватчик по-умолчанию, потом специфичный для класса, а за ним для метода. Если вы не хотите чтобы для вашего метода вызывался перехватчик по-умолчанию - используйте аннотацию @ExcludeDefaultInterceptors или @ExcludeClassInterceptors.* com.example.MyLogger
Я требую продолжения банкета! Даёшь "Основы EJB: часть 2"
ОтветитьУдалитьспасибо за краткое и подробное объяснение компонентов EJB. Хотелось бы продолжения :)
ОтветитьУдалитьa дальше наверное по книжкам)
УдалитьКласс!
ОтветитьУдалить