Jakarta Enterprise Beans ( EJB ; ранее Enterprise JavaBeans ) — один из нескольких API Java для модульного построения корпоративного программного обеспечения . EJB — это серверный программный компонент , который инкапсулирует бизнес-логику приложения. Веб-контейнер EJB предоставляет среду выполнения для веб-компонентов программного обеспечения, включая компьютерную безопасность , управление жизненным циклом сервлетов Java , обработку транзакций и другие веб-сервисы . Спецификация EJB является подмножеством спецификации Java EE . [1]
Спецификация EJB была первоначально разработана в 1997 году компанией IBM , а затем принята компанией Sun Microsystems (EJB 1.0 и 1.1) в 1999 году [2] и улучшена в рамках Java Community Process как JSR 19 (EJB 2.0), JSR 153 (EJB 2.1), JSR 220 (EJB 3.0), JSR 318 (EJB 3.1) и JSR 345 (EJB 3.2).
Спецификация EJB предоставляет стандартный способ реализации серверного (также называемого « бэк-энд ») «бизнес» программного обеспечения, которое обычно встречается в корпоративных приложениях (в отличие от «фронт-энд» пользовательского интерфейса ). Такое программное обеспечение решает те же типы проблем, и решения этих проблем часто многократно реализуются программистами. Jakarta Enterprise Beans предназначен для решения таких общих проблем, как сохранение , транзакционная целостность и безопасность стандартным способом, позволяя программистам сосредоточиться на конкретных частях корпоративного программного обеспечения.
Спецификация EJB подробно описывает, как сервер приложений выполняет следующие обязанности:
Кроме того, спецификация Jakarta Enterprise Beans определяет роли, которые играют контейнер EJB и EJB, а также как развертывать EJB в контейнере. Обратите внимание, что спецификация EJB не описывает, как сервер приложений обеспечивает сохранение (задача, делегированная спецификации JPA), но вместо этого описывает, как бизнес-логика может легко интегрироваться с услугами сохранения, предлагаемыми сервером приложений.
Предприятия обнаружили, что использование EJB для инкапсуляции бизнес-логики привело к потере производительности. Это связано с тем, что исходная спецификация допускала только удаленный вызов методов через CORBA (и опционально другие протоколы), хотя подавляющее большинство бизнес-приложений на самом деле не требуют этой распределенной вычислительной функциональности. Спецификация EJB 2.0 решила эту проблему, добавив концепцию локальных интерфейсов, которые можно было вызывать напрямую без потери производительности приложениями, не распределенными по нескольким серверам. [3]
Спецификация EJB 3.0 ( JSR 220) была отходом от своих предшественников, следуя новой облегченной парадигме. EJB 3.0 демонстрирует влияние Spring в использовании простых объектов Java и поддержке внедрения зависимостей для упрощения настройки и интеграции гетерогенных систем. EJB 3.0 вместе с другими версиями EJB можно интегрировать с MuleSoft -v4 с помощью сертифицированного MuleSoft коннектора PlektonLabs EJB. Гэвин Кинг, создатель Hibernate , участвовал в процессе EJB 3.0 и является ярым сторонником этой технологии. Многие функции, изначально присутствующие в Hibernate, были включены в Java Persistence API , замену компонентам сущностей в EJB 3.0. Спецификация EJB 3.0 в значительной степени опирается на использование аннотаций (функция, добавленная в язык Java с выпуском 5.0) и соглашения по конфигурации , чтобы обеспечить гораздо менее многословный стиль кодирования. Соответственно, с практической точки зрения EJB 3.0 гораздо более легкий и практически представляет собой совершенно новый API, мало похожий на предыдущие спецификации EJB. [ необходима цитата ]
Ниже показан базовый пример того, как выглядит EJB в коде:
@Stateless публичный класс CustomerService { private EntityManager entityManager ; public void addCustomer ( Customer ) { entityManager.persistent ( Customer ) ; } }
Вышеуказанный пример определяет класс обслуживания для сохранения объекта Customer (через O/R-отображение ). EJB заботится об управлении контекстом сохранения, а метод addCustomer() является транзакционным и потокобезопасным по умолчанию. Как показано, EJB фокусируется только на бизнес-логике и сохранении и ничего не знает о каком-либо конкретном представлении.
Такой EJB может использоваться классом, например, в веб-слое следующим образом:
@Named @RequestScoped public class CustomerBacking { @EJB private CustomerService customerService ; public String addCustomer ( Customer customer ) { customerService . addCustomer ( customer ); context . addMessage (...); // сокращено для краткости return "customer_overview" ; } }
Вышеуказанное определяет компонент JavaServer Faces (JSF), в который EJB внедряется посредством @EJB
аннотации. Его метод addCustomer обычно привязан к некоторому компоненту пользовательского интерфейса, например к кнопке. В отличие от EJB, компонент поддержки не содержит никакой бизнес-логики или кода сохранения, но делегирует такие заботы EJB. Компонент поддержки знает о конкретном представлении, о котором EJB не имел никаких знаний.
Контейнер EJB содержит два основных типа компонентов:
Сессионные компоненты с сохранением состояния [7] — это бизнес-объекты, имеющие состояние : то есть они отслеживают, с каким вызывающим клиентом они имеют дело в течение сеанса, а также историю его запросов, и, таким образом, доступ к экземпляру компонента строго ограничен только одним клиентом в течение его жизненного цикла. [8] Если в любом случае предпринимается попытка одновременного доступа к одному компоненту, контейнер сериализует эти запросы, но с помощью @AccessTimeout
аннотации контейнер может вместо этого выдать исключение. [9] Состояние сессионных компонентов с сохранением состояния может автоматически сохраняться (пассивироваться) контейнером для освобождения памяти после того, как клиент не обращался к компоненту в течение некоторого времени. Расширенный контекст сохранения JPA явно поддерживается сессионными компонентами с сохранением состояния. [10]
Сессионные компоненты без состояния [11] — это бизнес-объекты, не имеющие связанного с ними состояния. Однако доступ к одному экземпляру компонента по-прежнему ограничен только одним клиентом за раз, одновременный доступ к компоненту запрещен. [8] При попытке одновременного доступа к одному компоненту контейнер просто направляет каждый запрос другому экземпляру. [12] Это делает сессионный компонент без состояния автоматически потокобезопасным. Переменные экземпляра могут использоваться во время одного вызова метода от клиента к компоненту, но не гарантируется сохранение содержимого этих переменных экземпляра при различных вызовах методов клиента . Экземпляры сессионных компонентов без состояния обычно объединяются в пул. Если второй клиент обращается к определенному компоненту сразу после завершения вызова метода, выполненного первым клиентом, он может получить тот же экземпляр. Отсутствие накладных расходов на поддержание диалога с вызывающим клиентом делает их менее ресурсоемкими, чем компоненты с сохранением состояния.
Singleton Session Beans [13] [14] — это бизнес-объекты, имеющие глобальное общее состояние в JVM. Параллельный доступ к одному и единственному экземпляру bean-компонента может контролироваться контейнером (Container-managed concurrency, CMC) или самим bean-компонентом (Bean-managed concurrency, BMC). CMC можно настроить с помощью аннотации @Lock
, которая указывает, будет ли использоваться блокировка чтения или блокировка записи для вызова метода. Кроме того, Singleton Session Beans могут явно запрашивать создание экземпляра при запуске контейнера EJB, используя @Startup
аннотацию.
Message Driven Beans [15] — это бизнес-объекты, выполнение которых запускается сообщениями, а не вызовами методов. Message Driven Bean используется среди прочего для предоставления абстракции высокого уровня простоты использования для спецификации JMS ( Java Message Service ) нижнего уровня. Он может подписываться на очереди сообщений JMS или темы сообщений, что обычно происходит через атрибут activationConfig аннотации @MessageDriven
. Они были добавлены в EJB для обеспечения обработки, управляемой событиями. В отличие от сессионных компонентов, MDB не имеет клиентского представления (локального/удалённого/без интерфейса), т. е. клиенты не могут искать экземпляр MDB. MDB просто прослушивает любые входящие сообщения, например, в очереди или теме JMS, и обрабатывает их автоматически. Спецификация Java EE требует только поддержки JMS, [16] но Message Driven Beans может поддерживать другие протоколы обмена сообщениями. [17] [18] Такие протоколы могут быть асинхронными, но также могут быть синхронными. Поскольку сессионные компоненты могут быть как синхронными, так и асинхронными, основное различие между сессионными компонентами и компонентами, управляемыми сообщениями, заключается не в синхронности, а в разнице между (объектно-ориентированным) вызовом методов и обменом сообщениями .
EJB-компоненты развертываются в контейнере EJB, обычно на сервере приложений . Спецификация описывает, как EJB взаимодействует со своим контейнером и как клиентский код взаимодействует с комбинацией контейнер/EJB. Классы EJB, используемые приложениями, включены в javax.ejb
пакет. ( javax.ejb.spi
Пакет представляет собой интерфейс поставщика услуг , используемый только реализациями контейнера EJB.)
Клиенты EJB не создают экземпляры этих bean-компонентов напрямую через оператор Java new, а вместо этого должны получить ссылку через контейнер EJB. Эта ссылка обычно не является ссылкой на сам bean-компонент реализации, а на proxy , который динамически реализует либо локальный, либо удаленный бизнес-интерфейс, запрошенный клиентом, либо подтип фактического bean-компонента. Затем proxy может быть напрямую приведен к интерфейсу или bean-компоненту соответственно. Говорят, что у клиента есть «представление» на EJB, а локальный интерфейс, удаленный интерфейс и сам подтип bean-компонента соответственно соответствуют локальному представлению, удаленному представлению и представлению без интерфейса.
Этот прокси необходим для того, чтобы дать контейнеру EJB возможность прозрачно предоставлять сквозные ( AOP -подобные) сервисы для bean-компонента, такие как транзакции, безопасность, перехваты, инъекции и удаленное взаимодействие. Например, клиент вызывает метод на прокси-компоненте, который сначала начнет транзакцию с помощью контейнера EJB, а затем вызовет фактический метод bean-компонента. Когда метод bean-компонента возвращается, прокси завершает транзакцию (т. е. фиксирует ее или выполняет откат) и передает управление обратно клиенту.
Контейнер EJB отвечает за обеспечение клиентского кода достаточными правами доступа к EJB. [20] Аспекты безопасности могут быть декларативно применены к EJB с помощью аннотаций. [21]
Контейнеры EJB должны поддерживать как управляемые контейнером транзакции ACID , так и управляемые компонентами транзакции. [22]
Контейнерно-управляемые транзакции (CMT) по умолчанию активны для вызовов сессионных компонентов. То есть, явная настройка не требуется. Это поведение может быть декларативно настроено компонентом с помощью аннотаций, и при необходимости такая конфигурация может быть позже переопределена в дескрипторе развертывания. Настройка включает отключение транзакций для всего компонента или определенных методов или запрос альтернативных стратегий для распространения транзакций и запуска или присоединения к транзакции. Такие стратегии в основном имеют дело с тем, что должно произойти, если транзакция уже выполняется или не выполняется во время вызова компонента. Поддерживаются следующие варианты: [23] [24]
В качестве альтернативы, бин может также объявить через аннотацию, что он хочет обрабатывать транзакции программно через JTA API. Этот режим работы называется Bean Managed Transactions (BMT), поскольку сам бин обрабатывает транзакцию вместо контейнера. [25]
JMS ( Java Message Service ) используется для отправки сообщений от bean-компонентов клиентам, чтобы позволить клиентам получать асинхронные сообщения от этих bean-компонентов. MDB могут использоваться для получения сообщений от клиентов асинхронно с использованием либо JMS Queue, либо Topic.
В качестве альтернативы внедрению клиенты EJB могут получить ссылку на прокси-объект сессионного компонента (заглушку EJB) с помощью интерфейса именования и каталогов Java (JNDI) . Эту альтернативу можно использовать в случаях, когда внедрение недоступно, например, в неуправляемом коде или автономных удаленных клиентах Java SE, или когда необходимо программно определить, какой компонент получить.
Имена JNDI для сессионных компонентов EJB назначаются контейнером EJB по следующей схеме: [26] [27] [28]
(записи в квадратных скобках обозначают необязательные части)
Одиночный компонент может быть получен по любому имени, соответствующему вышеуказанным шаблонам, в зависимости от «местоположения» клиента. Клиенты в том же модуле, что и требуемый компонент, могут использовать область действия модуля и более крупные области действия, клиенты в том же приложении, что и требуемый компонент, могут использовать область действия приложения и более крупные области действия и т. д.
Например, код, работающий в том же модуле, что и компонент CustomerService (как показано в примере, показанном ранее в этой статье), может использовать следующий код для получения (локальной) ссылки на него:
CustomerServiceLocal customerService = ( CustomerServiceLocal ) new InitialContext (). lookup ( "java:module/CustomerService" );
Для связи с клиентом, написанным на языке программирования Java, сессионный компонент может предоставлять удаленное представление через интерфейс, аннотированный с помощью @Remote
. [29] Это позволяет вызывать эти компоненты из клиентов в других JVM , которые могут работать в других системах (с точки зрения контейнера EJB любой код в другой JVM является удаленным).
Сессионные компоненты без сохранения состояния и Singleton также могут предоставлять «клиентское представление веб-службы» для удаленной связи через WSDL и SOAP или простой XML. [30] [31] [32] Это соответствует спецификациям JAX-RPC и JAX-WS . Однако предлагается исключить поддержку JAX-RPC в будущем. [33] Для поддержки JAX-WS сессионный компонент аннотируется с помощью @WebService
, а методы, которые должны быть представлены удаленно, — с помощью @WebMethod
.
Хотя спецификация EJB не упоминает раскрытие как RESTful веб-сервисов каким-либо образом и не имеет явной поддержки для этой формы коммуникации, спецификация JAX-RS явно поддерживает EJB. [34] Согласно спецификации JAX-RS, Stateless и Singleton сессионные компоненты могут быть объявлены как корневые ресурсы через аннотацию @Path
, а бизнес-методы EJB могут быть сопоставлены с методами ресурсов через аннотации @GET
, @PUT
, @POST
и @DELETE
. Однако это не считается «клиентским представлением веб-сервиса», которое используется исключительно для JAX-WS и JAX-RPC.
Связь через веб-сервисы типична для клиентов, не написанных на языке программирования Java, но также удобна для клиентов Java, у которых возникают проблемы с доступом к серверу EJB через брандмауэр. Кроме того, связь на основе веб-сервисов может использоваться клиентами Java для обхода скрытых и плохо определенных требований для так называемых «клиентских библиотек»; набора jar-файлов, которые клиент Java должен иметь в своем class-path для связи с удаленным сервером EJB. Эти клиентские библиотеки потенциально конфликтуют с библиотеками, которые у клиента могут уже быть (например, если сам клиент также является полным сервером Java EE), и такой конфликт считается очень сложным или невозможным для разрешения. [35]
С EJB 2.1 и более ранними версиями каждый EJB должен был предоставлять класс реализации Java и два интерфейса Java. Контейнер EJB создавал экземпляры класса реализации Java для предоставления реализации EJB. Интерфейсы Java использовались клиентским кодом EJB.
В EJB 2.1 и более ранних версиях спецификация EJB требовала наличия дескриптора развертывания. Это было необходимо для реализации механизма, который позволял развертывать EJB-компоненты согласованным образом независимо от выбранной платформы EJB. Информация о том, как следует развертывать компонент (например, имя домашнего или удаленного интерфейсов, следует ли и как хранить компонент в базе данных и т. д.), должна была быть указана в дескрипторе развертывания.
Дескриптор развертывания — это XML- документ, содержащий запись для каждого EJB, который должен быть развернут. Этот XML-документ определяет следующую информацию для каждого EJB:
Старые контейнеры EJB от многих поставщиков требовали больше информации о развертывании, чем указано в спецификации EJB. Им требовалась дополнительная информация в виде отдельных XML-файлов или какого-либо другого формата файла конфигурации. Поставщик платформы EJB обычно предоставлял собственные инструменты, которые считывали этот дескриптор развертывания и, возможно, генерировали набор классов, которые реализовывали бы устаревшие интерфейсы Home и Remote.
Начиная с EJB 3.0 (JSR 220), дескриптор XML заменяется аннотациями Java, установленными в реализации Enterprise Bean (на уровне источника), хотя по-прежнему возможно использовать дескриптор XML вместо (или в дополнение к) аннотаций. Если дескриптор XML и аннотации применяются к одному и тому же атрибуту в Enterprise Bean, определение XML переопределяет соответствующую аннотацию на уровне источника, хотя некоторые элементы XML также могут быть аддитивными (например, activation-config-property в XML с именем, отличным от уже определенного с помощью @ActivationConfigProperty
аннотации, будет добавлен вместо замены всех существующих свойств).
Начиная с EJB 3.1, спецификация EJB определяет два варианта контейнера EJB: полную версию и ограниченную версию. Ограниченная версия придерживается надлежащего подмножества спецификации, называемого EJB 3.1 Lite [36] [37] , и является частью веб-профиля Java EE 6 (который сам по себе является подмножеством полной спецификации Java EE 6).
EJB 3.1 Lite исключает поддержку следующих функций: [38]
@Schedule
, @Timeout
)@Asynchronous
)EJB 3.2 Lite исключает меньше функций. В частности, он больше не исключает @Asynchronous
и @Schedule
/ @Timeout
, но @Schedule
не поддерживает атрибут "persistent", который поддерживает полная версия EJB 3.2. Полный список исключений для EJB 3.2 Lite:
@Schedule
)EJB 4.0, финальная версия (2020-05-22)
Jakarta Enterprise Beans 4.0, как часть Jakarta EE 9, был выпуском инструментария, который в основном перемещал имена пакетов API из javax.ejb
пакета верхнего уровня в пакет верхнего уровня jakarta.ejb
. [39]
Другие изменения включали удаление устаревших API, которые не имели смысла переносить в новый пакет верхнего уровня, а также удаление функций, зависящих от функций, удаленных из Java или из других источников в Jakarta EE 9. Были удалены следующие API:
java.security.Identity
, были удалены из Java 14.EJBContext.getEnvironment()
метод.Другие незначительные изменения включают пометку группы API Enterprise Beans 2.x как «необязательной» и возможность Schedule
повторять аннотацию.
EJB 3.2.6, финальная версия (2019-08-23)
Jakarta Enterprise Beans 3.2, как часть Jakarta EE 8, и несмотря на то, что по-прежнему используется аббревиатура «EJB», этот набор API был официально переименован в «Jakarta Enterprise Beans» организацией Eclipse Foundation, чтобы не наступать на торговую марку Oracle «Java».
EJB 3.2, финальная версия (28.05.2013)
JSR 345. Enterprise JavaBeans 3.2 был относительно небольшим релизом, который в основном содержал разъяснения спецификации и снял некоторые ограничения, наложенные спецификацией, но со временем, как оказалось, не служил никакой реальной цели. Несколько существующих полных функций EJB также были востребованы для включения в EJB 3 lite, а функциональность, которую предлагалось сократить в EJB 3.1, действительно была сокращена (стала необязательной). [40] [41]
Были добавлены следующие функции:
@Stateful
аннотации (passivationCapable = false)@PostConstruct
) могут быть транзакционными для сессионных компонентов с сохранением состояния, используя существующую @TransactionAttribute
аннотациюEJB 3.1, финальная версия (10.12.2009)
JSR 318. Целью спецификации Enterprise JavaBeans 3.1 является дальнейшее упрощение архитектуры EJB за счет снижения ее сложности с точки зрения разработчика, а также добавление новых функций в ответ на потребности сообщества:
@Asynchronous
для сессионных компонентов)EJB 3.0, финальная версия (11.05.2006)
JSR 220 — Основные изменения : В этом выпуске стало намного проще писать EJB, используя «аннотации» вместо сложных «дескрипторов развертывания», которые использовались в версии 2.x. Использование домашних и удаленных интерфейсов, а также файла ejb-jar.xml также больше не требовалось в этом выпуске, поскольку они были заменены бизнес-интерфейсом и компонентом, реализующим интерфейс.
EJB 2.1, финальная версия (24.11.2003)
JSR 153 - Основные изменения :
EJB 2.0, финальная версия (22.08.2001)
JSR 19 - Основные изменения : Общие цели :
EJB 1.1, финальная версия (1999-12-17)
Основные изменения :
Цели версии 1.1:
EJB 1.0 (1998-03-24)
Анонсировано на JavaOne 1998 , [42] третьей конференции разработчиков Java компании Sun (с 24 по 27 марта). Цели для версии 1.0: