В следующей главе объясняется жизненный цикл разных сессионных EJB-компонентов и описывается, как можно осуществлять взаимодействие с использованием аннотаций обратных вызовов. Кроме того, вы узнаете, как применять расширенный инструмент TimerService для планирования задач, а также как задавать проверку прав на доступ.
Глава 8. Функции обратного вызова, служба таймера и авторизация
Из предыдущей главы вы узнали, что сеансовые компоненты управляются контейнером. Они располагаются в контейнере EJB, который незаметно обертывает бизнес-логику с помощью некоторых служб (внедрение зависимостей, управление транзакциями и т. д.). Рассмотрим три такие службы: управление жизненным циклом, планирование и авторизацию.
Жизненный цикл означает, что компонент-сеанс проходит через предопределенный набор переходов между состояниями. В зависимости от вида вашего компонента (хранящие/не хранящие состояние либо синглтоны) жизненный цикл будет состоять из различных состояний. Каждый раз, когда контейнер изменяет состояние жизненного цикла, он может вызывать методы, которые аннотированы как методы обратного вызова.
Служба таймера EJB является стандартным решением вопросов планирования задач. Корпоративные приложения, зависящие от уведомлений, основанных на календаре, используют эту службу для моделирования бизнес-процессов.
Защита данных также важна. Вы хотите, чтобы ваш бизнес-уровень действовал как брандмауэр и разрешал выполнять некоторые действия определенным группам пользователей и запрещал доступ остальным (например, только сотрудники имеют право сохранять данные, но и пользователи, и авторизованные сотрудники имеют право их считывать).
В этой главе вы узнаете, что сеансовый компонент, не хранящий состояние, а также синглтон могут иметь общий жизненный цикл, а жизненный цикл компонента, хранящего состояние, немного отличается. Вы также увидите, как компонент, не хранящий состояние, и синглтон могут использовать службу таймера для создания распределения задач по времени декларативно или программно. Эта глава заканчивается демонстрацией принципа работы авторизации в контейнере EJB. Кроме того, вы узнаете, как можно с легкостью позволить пользователям с определенными ролями получить доступ к вашему коду.
Жизненный цикл сеансовых компонентов
Как вы видели в предыдущей главе, клиент не создает экземпляр сеансового компонента с помощью оператора new. Он получает ссылку на сеансовый компонент либо с помощью внедрения зависимостей, либо через поиск JNDI. Созданием и разрушением экземпляров занимается контейнер. Это означает, что ни клиент, ни компонент не отвечают за определение момента, когда создается экземпляр компонента, когда внедряются зависимости или когда экземпляр уничтожается. Контейнер отвечает за управление жизненным циклом компонента.
Все сеансовые компоненты имеют две очевидные фазы их жизненного цикла: создание и разрушение. Кроме того, компоненты, сохраняющие состояние, имеют фазы пассивизации и активизации, упомянутые в предыдущей главе. EJB аналогично методам обратного вызова, используемым в сущностях, которые вы видели в предыдущих главах, позволяет контейнеру автоматически вызывать аннотированные методы (@PostConstruct, @PreDestroy и т. д.) на определенных этапах его жизненного цикла. Эти методы могут инициализировать информацию о состоянии компонента, искать ресурсы с помощью JNDI и освобождать соединения с базой данных.
Компоненты, не сохраняющие состояния, и синглтоны
Компоненты, не сохраняющие состояния, и синглтоны похожи друг на друга тем, что они не поддерживают состояние диалога с выделенным клиентом. Оба типа компонентов позволяют получить доступ к любому клиенту — компонент, не хранящий состояние, делает это для каждого экземпляра, в то время как синглтон предоставляет доступ к одному экземпляру. Компоненты обоих типов имеют одинаковые жизненные циклы (рис. 8.1), которые описываются следующим образом.
1. Жизненный цикл компонента без сохранения состояния и синглтона начинается, когда клиент запрашивает ссылку на компонент (с помощью внедрения зависимостей или поиска JNDI). Для синглтона он также может начаться, когда загружается контейнер (при этом используется аннотация @Startup). Контейнер создает новый экземпляр сеансового компонента.
2. Если вновь созданный экземпляр использует внедрение зависимостей через аннотации (@Inject, @Resource, @EJB, @PersistenceContext и т. д.) или развертывание дескрипторов, то контейнер внедряет все необходимые ресурсы.
3. Если экземпляр имеет метод с аннотацией @PostContruct, то контейнер вызывает его.
4. Экземпляр компонента обрабатывает вызов, созданный клиентом, и остается в режиме готовности к обработке будущих вызовов. Компоненты, не сохраняющие состояние, остаются в этом режиме до тех пор, пока контейнер не освободит место в хранилище. Синглтоны остаются в режиме готовности до тех пор, пока контейнер не будет выключен.