EJB¶
Спецификация для написания серверной бизнес-логики, которая работает внутри контейнера приложений.
EJB = упакованный бэкэнд-сервис с кучей инфраструктуры из коробки.
EJB из коробки дает:
- Транзакции
- Декларативно: @TransactionAttribute(REQUIRED) и т.п.
- Контейнер сам начинает/коммитит/откатывает транзакции.
- Безопасность
- Роли и доступ: @RolesAllowed("admin"), @PermitAll, @DenyAll.
- Контейнер проверяет права до входа в метод.
- Пул объектов
- Для @Stateless и MDB контейнер держит пул, чтобы быстро обслуживать много запросов.
- Таймеры
- Планировщик задач: @Schedule(hour="*", minute="0", second="0") и т.п.
- Remote / Local вызовы
- Можно объявить интерфейс как @Local или @Remote:
- Local — вызовы внутри того же приложения/процесса.
- Remote — через сеть (другое приложение, другой сервер).
Основные задачи¶
Вынести бизнес-логику в отдельный слой (отдельно от JSF/Servlet и т.п.)
пишутся просто классы с аннотациями, а контейнер EJB:
- создаёт/удаляет объекты,
- раздаёт их по пулу,
- включает транзакции,
- рулит безопасностью,
- даёт удалённый доступ (RMI, HTTP и т.п.),
- может обрабатывать сообщения (JMS).
Типы EJB¶
Session Beans - СИНХРОННЫЕ
@Stateless- Не хранит состояние между вызовами.
- Контейнер держит пул экземпляров и кидает любой на любой запцуирос.
- Подходит для типичных сервисов: UserService, OrderService и т.д.
@Stateful- Хранит состояние между вызовами для одного клиента (как “session”).
- Используется, когда логика зависит от последовательности шагов (wizard, корзина и т.п.).
@Singleton- Один экземпляр на приложение.
- Для кэшей, глобальных конфигов, счётчиков и т.п.
Message-Driven Beans - АСИНХРОННЫЕ
@MessageDriven— слушатель очереди (JMS).- Не вызывается напрямую, а реагирует на сообщения из брокера.
Жизненный цикл¶
- Жизненный цикл EJB по типам
2.1. Stateless Session Bean
Суть: не хранит состояние между вызовами; контейнер держит пул экземпляров.
Состояния:
- Does Not Exist Бина ещё нет.
- Pooled (Ready) Контейнер создал объект, вызвал @PostConstruct, положил в пул.
- Method Invocation Приходит вызов от клиента → контейнер берёт любой экземпляр из пула, оборачивает в транзакцию/безопасность → вызывает метод → возвращает в пул.
- Removed При остановке приложения или сокращении пула контейнер вызывает @PreDestroy и удаляет бин.
Жизненный цикл в картинке:
Does Not Exist → (create) → @PostConstruct → Pooled → (method call) → Pooled → ... → @PreDestroy → Removed
Особенности под капотом: • Клиент видит прокси, а не конкретный объект. • Никакой гарантии, что два вызова пойдут к одному и тому же экземпляру. • Контейнер может создать от 0 до N экземпляров, динамически увеличивая/уменьшая пул.
⸻
2.2. Stateful Session Bean
Суть: хранит состояние для конкретного клиента (один клиент → один бин).
Состояния:
- Does Not Exist
- Method-Ready (Active) Создан, прошёл @PostConstruct, готов обслуживать вызовы этого клиента.
- Passive (опционально) Контейнер может “усыпить” бин: • вызывает @PrePassivate, • сериализует состояние на диск/в память, • позже при необходимости: • десериализует, • вызывает @PostActivate.
- Removed • по @Remove-методу, • по тайм-ауту, • при остановке приложения → @PreDestroy.
Жизненный цикл:
Does Not Exist → (create) → @PostConstruct → Active → [@PrePassivate → Passive → @PostActivate → Active]* → @PreDestroy → Removed
Главное отличие от Stateless: • идентичность: конкретный клиент привязан к конкретному экземпляру, пока не будет @Remove; • возможна пассивизация, чтобы не держать их всех в памяти; • никакого пула “анонимных” экземпляров — каждый бин привязан к клиентскому “диалогу”.
⸻
2.3. Singleton Session Bean
Суть: один экземпляр на всё приложение.
Состояния:
- Does Not Exist
- Initialized • создаётся один раз, • вызывается @PostConstruct, • если стоит @Startup, создаётся при запуске приложения.
- Method-Ready Обслуживает запросы.
- Removed При остановке приложения → @PreDestroy.
Жизненный цикл:
Does Not Exist → @PostConstruct → Method-Ready → @PreDestroy → Removed
Особенности: • Конкурентность управляется аннотациями: • @Lock(READ) / @Lock(WRITE) — блокировки на уровне методов; • @ConcurrencyManagement(CONTAINER) (по умолчанию) или BEAN. • Часто используется как: • кэш, • глобальный сервис/реестр.
⸻
2.4. Message-Driven Bean (MDB)
Суть: слушатель очереди / топика (JMS).
Состояния похожи на Stateless:
- Does Not Exist
- Pooled Несколько экземпляров, каждый прошёл @PostConstruct.
- Message Delivery Приходит сообщение → контейнер выбирает бин из пула → вызывает onMessage() (или аналог).
- Removed При остановке или сокращении пула → @PreDestroy.
MDB не вызывается напрямую клиентом, только брокером/контейнером сообщения.
⸻
- Чем это отличается от CDI-жизненного цикла
CDI-бин: • Живёт по scope: • @RequestScoped → от начала до конца HTTP-запроса; • @SessionScoped → от начала до конца HTTP-сессии; • @ApplicationScoped → всё время жизни приложения; • @Dependent → живёт ровно столько, сколько его владелец. • Lifecycle обычно: • new → @PostConstruct (при первом использовании в своём scope) → рабочее состояние → @PreDestroy (при завершении scope). • Контейнер не обязан: • делать пулы, • пассивировать, • обеспечивать удалённый доступ, • автоматически оборачивать каждый метод в транзакции.
В EJB всё это входит в контракт: • чёткие правила, когда и сколько экземпляров может быть; • что происходит при конкуренции; • где проходят границы транзакций; • как ведут себя методы с @Remove, @PrePassivate, @PostActivate, @Schedule, и т.д.
⸻
Если хочешь, дальше можем взять, например, @Stateless и @RequestScoped CDI-бин и прямо по шагам сравнить: • кто создаётся когда, • кто кем кэшируется/пулится, • как ведут себя при нагрузке и многопоточности.
модель работы EJB
жизненный цикл singleton stateful stateless
вызов бина local remote
что имеется ввиду под транзакцией, безопасностью, пуллингом, удаленными вызовами, таймерами и JMS и контексте бина? подробне про то как работает: транзакцией, безопасностью, пуллингом, удаленными вызовами, таймерами и JMS.
Карта типов «бинов» в Jakarta EE
EJB (Enterprise Java Beans) — бизнес-компоненты с «тяжёлым» рантаймом: транзакции, безопасность, таймеры, асинхронность, пуллинг, (опционально) удалённые вызовы — «из коробки».
@Stateless — без состояния между вызовами; контейнер держит пул экземпляров. Хорошо для «сервисов».
@Stateful — состояние на клиента (сеанс); подходит для пошаговых/мастер-сценариев.
@Singleton — один экземпляр на приложение; есть управление конкурентным доступом.
@MessageDriven — обработчик сообщений JMS (асинхронный consumer).
Интерфейсы доступа: @Local, @Remote (для ремоута), @LocalBean (без интерфейса).
Транзакции: @TransactionAttribute(REQUIRED|REQUIRES_NEW|MANDATORY|SUPPORTS|NOT_SUPPORTED|NEVER),
@TransactionManagement(BEAN|CONTAINER).
Безопасность: @RolesAllowed, @PermitAll, @DenyAll, @RunAs.
Асинхронность: @Asynchronous (возврат Future/CompletionStage или void).
Таймеры: @Schedule(cron-like), @Schedules, @Timeout.
Жизненный цикл: @PostConstruct, @PreDestroy; для @Stateful — @Remove.
Для @Singleton: конкурентность @Lock(READ|WRITE), таймаут @AccessTimeout(ms).
CDI-бины (Context and Dependency Injection) — универсальные управляемые контейнером классы: DI, скоупы, квалификаторы, события, продьюсеры, перехватчики, декораторы. Лёгкие, гибкие, часто основной выбор.
Внедрение: @Inject (в поля/конструкторы/сеттеры).
Именование для EL/JSF: @Named("name") (или без имени — берётся по умолчанию).
Квалификаторы (маркировка реализаций): @Qualifier + собственные аннотации (например, @PrimaryDb, @Mock).
Продьюсеры/диспозеры: @Produces (создание бина/ресурса), @Disposes (закрытие).
Стереотипы: @Stereotype — собрать набор аннотаций в одну.
Скоупы (контексты)
@ApplicationScoped — один на приложение.
@SessionScoped — на HTTP-сессию.
@RequestScoped — на запрос.
@ConversationScoped — управляемая «длинная» беседа (JSF use-case).
@Dependent — «без собственного контекста»: живёт столько, сколько потребитель (по умолчанию).
Перехватчики/декораторы/события
Перехватчики: @Interceptor + @AroundInvoke / @AroundConstruct; включение через @Priority или beans.xml.
Декораторы: @Decorator для прокидывания вызовов и добавления поведения.
События: Event<T>/@Observes/@ObservesAsync.
Транзакции и безопасность в CDI
Можно добавлять @Transactional (из jakarta.transaction) на методы CDI-бина для контейнерных транзакций.
Безопасность — через Jakarta Security или интеграцию сервера (также есть аннотации на методах/классах).
JSF Managed Beans — устаревающее именование для Faces-бинов; сейчас вместо @ManagedBean почти всегда используют CDI + @Named.
Старый стиль: @ManagedBean, @RequestScoped/@SessionScoped из jakarta.faces.bean.*, @ViewScoped и т.д.
Современный стиль: CDI + @Named + JSF-скоупы (например, @ViewScoped из jakarta.faces.view.ViewScoped) или обычные CDI-скоупы.
Практика сегодня: не использовать @ManagedBean; использовать CDI-бины, чтобы иметь полноценный DI и кросс-интеграцию.
JAX-RS ресурсы — классы-ресурсы REST (не «бины» по названию, но управляются контейнером и дружат с CDI).
JPA Entities — сущности данных (POJO), не «бины» бизнес-логики, но часто инжектятся в бины через EntityManager.