Контейнер является частью модели
EJB-компонент не сводится к обычному классу с удачным названием. Контейнер управляет его жизненным циклом и предоставляет предусмотренные платформой службы, включая внедрение зависимостей, управление транзакциями и проверки доступа. Клиент получает управляемую ссылку через соответствующие механизмы платформы. Аннотация @Stateless описывает тип компонента, но не превращает любой объект, созданный оператором new, в управляемый экземпляр EJB. Поэтому обычная проверка метода как Java-кода и проверка поведения компонента в контейнере решают разные задачи. Успех первой не подтверждает автоматически настройки второй.
Stateless не хранит диалог клиента между вызовами
Контейнер может обслуживать вызовы разными экземплярами из пула. Клиент не должен предполагать, что следующий метод попадёт в тот же объект и найдёт там его персональные значения. При этом поля у объекта могут существовать, а данные способны сохраняться в экземпляре между обращениями. Представим ошибочный замысел: одним вызовом установить клиента в поле, другим получить расчёт для него. Для stateless-компонента такая связка ненадёжна. Безопаснее передавать все необходимые параметры операции в одном вызове либо использовать подходящее явно спроектированное хранение. Значения предыдущего клиента не должны становиться неявной основой нового расчёта.
Stateful и постоянное хранение решают разные задачи
Stateful session bean предназначен для состояния конкретного взаимодействия клиента с компонентом. Например, несколько последовательных действий могут изменять временный набор выбранных позиций. Это отличается от операции, которая каждый раз получает полный набор входных данных и возвращает результат. Однако stateful сам по себе не означает запись в базу данных. Сохранность оформленного заказа после завершения взаимодействия требует отдельного решения о постоянном хранении. Полезно различать три срока жизни: данные одного вызова, состояние диалога и сведения, которые должны пережить его завершение. Выбор компонента начинается с этого различия, а не с привычки использовать один тип везде.
Не выводите границы транзакции из количества методов
При контейнерном управлении границы транзакции зависят от заданных атрибутов. Например, Required использует текущую транзакцию вызывающего кода, если она есть, либо приводит к началу новой при её отсутствии. Поэтому несколько вызовов могут участвовать в одной транзакции. Тип stateless или stateful не заменяет проверки этих настроек. Для анализа нарисуйте путь вызова и отметьте, где находится состояние, кто управляет транзакцией и какие данные сохраняются постоянно. Затем проверьте сценарии двух клиентов и завершения диалога. Такая схема помогает обнаружить неверные предположения ещё до обсуждения подробностей реализации.
Попробуйте на практике
Разберите на бумаге три серверные задачи и определите требования к состоянию.
- Запишите задачи: рассчитать итог по переданным позициям, накапливать временную корзину в нескольких вызовах и хранить оформленный заказ.
- Для каждой задачи укажите, нужны ли данные только во время вызова, на время диалога или после его завершения.
- Объясните, почему установка идентификатора клиента в поле stateless-компонента не гарантирует его сохранения для следующего вызова того же клиента.
- Отметьте, что stateful-корзина не заменяет постоянное хранение оформленного заказа.
- Добавьте вопрос о транзакционном атрибуте и наличии транзакции у вызывающей стороны, не считая каждый метод отдельной транзакцией автоматически.
Как проверить результат. Различены состояние вызова, диалога и постоянные данные. Stateless не используется как персональная память между обращениями, а управляемый компонент не приравнен к произвольно созданному Java-объекту.
Частые вопросы
У stateless-компонента обязательно должны быть только статические методы?
Нет. Stateless относится к управлению разговорным состоянием клиента, а не к требованию объявлять бизнес-методы статическими.
Для корзины всегда нужен stateful-компонент?
Не обязательно. Состояние можно спроектировать и во внешнем хранилище, используя операции без сохранения диалога в экземпляре. Выбор зависит от архитектурных требований и срока жизни данных.
Самостоятельный разбор темы. Содержание конкретной обучающей программы здесь не представлено.