Теперь, когда вы уже видели примеры сессионных EJB-компонентов и их различных интерфейсов, вам, возможно, хочется взглянуть на то, как клиент вызывает эти EJB-компоненты. Клиентом сессионного EJB-компонента может быть любой компонент: POJO, графический интерфейс (Swing), управляемый CDI MBean-компонент, сервлет, EJB-компонент JSF, являющийся подложкой, веб-служба (SOAP или REST) либо другой EJB-компонент (развернутый в том же или другом контейнере).
На стороне клиента также все просто. Чтобы вызвать метод в сессионном EJB-компоненте, клиент не создает экземпляр соответствующего EJB-компонента непосредственным образом (с использованием оператора new). Ему нужна ссылка на этот EJB-компонент (или на его интерфейсы). Он может получить ее при внедрении зависимостей (с использованием аннотации @EJB или @Inject) либо с помощью JNDI-поиска. Внедрение зависимостей позволяет контейнеру автоматически внедрять ссылку на EJB-компонент во время развертывания. Если не предусмотрено иное, то клиент будет вызывать сессионный EJB-компонент синхронно.
Вызов с использованием внедрения
Java EE задействует несколько аннотаций для внедрения ссылок на ресурсы (@Resource), менеджера сущностей (@PersistenceContext), веб-службы (@WebServiceRef) и т. д. Аннотация @javax.ejb.EJB специально предназначена для внедрения ссылок на сессионные EJB-компоненты в клиентский код. Внедрение зависимостей возможно только в управляемых средах вроде EJB-контейнеров, веб-контейнеров и контейнеров клиентских приложений.
Обратимся к нашим исходным примерам, в которых сессионные EJB-компоненты не обладали интерфейсом. Чтобы клиент смог вызвать представление без интерфейса сессионного EJB-компонента, ему необходимо получить ссылку на сам класс EJB-компонента. Например, в приведенном далее коде клиент получает ссылку на класс ItemEJB с использованием аннотации @EJB:
@Stateless
public class ItemEJB {…}
// Клиентский код с внедрением ссылки на EJB-компонент
@EJB ItemEJB itemEJB;
Если сессионный EJB-компонент реализует несколько интерфейсов, клиенту придется указать, на какой из них ему требуется ссылка. В приведенном далее коде ItemEJB реализует два интерфейса и благодаря аннотации @LocalBean также обеспечивает представление без интерфейса. Клиент может вызвать EJB-компонент с помощью его локального представления, удаленного представления или представления без интерфейса:
@Stateless
@Remote(ItemRemote.class)
@Local(ItemLocal.class)
@LocalBean
public class ItemEJB implements ItemLocal, ItemRemote {…}
// Клиентский код с внедрением нескольких ссылок на EJB-компонент или интерфейсы
@EJB ItemEJB itemEJB;
@EJB ItemLocal itemEJBLocal;
@EJB ItemRemote itemEJBRemote;
У API @EJB имеется несколько атрибутов. Один из них — JNDI-имя EJB-компонента, который вы хотите внедрить. Оно может быть особенно полезно при работе с удаленными EJB-компонентами, располагающимися на другом сервере:
@EJB(lookup = "java: global/classes/ItemEJB") ItemRemote itemEJBRemote;
Вызов с использованием CDI
Как вы только что видели, для вызова метода в EJB-компоненте требуется только аннотация @EJB, позволяющая внедрить ссылку в клиентский код. Все довольно просто: вы получаете ссылку во время развертывания. Однако @EJB не обеспечивает, например, чего-то подобного CDI-альтернативам. Взамен вам придется использовать аннотацию @Inject.
В большинстве случаев вы можете просто заменять @EJB аннотацией @Inject, и ваш клиентский код будет работать. Сделав это, вы получите все преимущества CDI, которые видели в главе 2. Таким образом, если мы обратимся к приведенным ранее примерам, то вот как обеспечивалось бы EJB-внедрение с использованием CDI в случае с клиентом:
@Stateless
@Remote(ItemRemote.class)
@Local(ItemLocal.class)
@LocalBean
public class ItemEJB implements ItemLocal, ItemRemote {…}
// Клиентский код с внедрением нескольких ссылок на EJB-компонент или интерфейсы посредством @Inject
@Inject ItemEJB itemEJB;
@Inject ItemLocal itemEJBLocal;
@Inject ItemRemote itemEJBRemote;