Перейти к основному содержимому

Введение в поиск EJB JNDI на сервере приложений WildFly

· 6 мин. чтения

1. Обзор

Enterprise Java Beans (EJB) — это основная часть спецификации Java EE , направленная на упрощение разработки распределенных приложений корпоративного уровня. Жизненный цикл EJB обрабатывается сервером приложений, таким как JBoss WildFly или Oracle GlassFish .

Компоненты EJB обеспечивают надежную модель программирования, которая облегчает внедрение программных модулей уровня предприятия, поскольку сервер приложений должен решать вопросы, не связанные с бизнес-логикой, такие как обработка транзакций, управление жизненным циклом компонентов или внедрение зависимостей.

Кроме того, мы уже опубликовали две статьи, посвященные основным концепциям EJB, поэтому не стесняйтесь ознакомиться с ними здесь и здесь .

В этом руководстве мы покажем, как реализовать базовый модуль EJB на WildFly и вызвать EJB с удаленного клиента через JNDI .

2. Реализация модуля EJB

Бизнес-логика реализуется одним или несколькими локальными/удаленными бизнес-интерфейсами (также известными как локальные/удаленные представления) или напрямую через классы, которые не реализуют интерфейс (интерфейсы без представлений).

Стоит отметить, что локальные бизнес-интерфейсы используются, когда доступ к компоненту будет осуществляться с клиентов, которые находятся в той же среде, т. е. с одним и тем же файлом EAR или WAR, тогда как удаленные бизнес-интерфейсы необходимы, когда доступ к компоненту будет осуществляться из другой среды. , то есть другой JVM или сервер приложений.

Давайте создадим базовый модуль EJB, который будет состоять всего из одного компонента. Бизнес-логика компонента будет простой и ограничивается преобразованием данной строки в ее версию в верхнем регистре.

2.1. Определение удаленного бизнес-интерфейса

Давайте сначала определим один единственный удаленный бизнес-интерфейс, украшенный аннотацией @Remote . Это обязательно в соответствии со спецификацией EJB 3.x , поскольку доступ к bean-компоненту будет осуществляться с удаленного клиента:

@Remote
public interface TextProcessorRemote {
String processText(String text);
}

2.2. Определение компонента без сохранения состояния

Далее реализуем бизнес-логику, реализовав вышеупомянутый удаленный интерфейс:

@Stateless
public class TextProcessorBean implements TextProcessorRemote {
public String processText(String text) {
return text.toUpperCase();
}
}

Класс TextProcessorBean — это простой класс Java, украшенный аннотацией @Stateless .

Bean-компоненты без сохранения состояния по определению не поддерживают никакого диалогового состояния со своими клиентами, даже если они могут поддерживать состояние экземпляра для разных запросов. Их аналог, bean-компоненты с отслеживанием состояния, сохраняют свое диалоговое состояние, и, например, их создание для сервера приложений обходится дороже.

Поскольку в этом случае вышеприведенный класс не имеет состояния экземпляра, его можно сделать без состояния. В случае, если у него есть состояние, его использование для разных клиентских запросов вообще не имеет смысла.

Поведение bean-компонента детерминировано, т. е. у него нет побочных эффектов, как и должно быть у хорошо спроектированного bean-компонента: он просто принимает входную строку и возвращает ее версию в верхнем регистре.

2.3. Зависимости Maven

Затем нам нужно добавить в модуль артефакт javaee-api Maven, который предоставляет все API-интерфейсы спецификации Java EE 7, в том числе необходимые для EJB:

<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>

На данный момент нам удалось создать базовый, но функциональный модуль EJB. Чтобы сделать его доступным для всех потенциальных клиентов, мы должны добавить артефакт в наш локальный репозиторий Maven в виде файла JAR.

2.4. Установка модуля EJB в локальный репозиторий

Есть несколько способов добиться этого. Самый простой из них состоит в выполнении этапов сборки жизненного цикла Maven clean-install :

mvn clean install

Эта команда устанавливает модуль EJB как ejbmodule-1.0.jar ( или любой произвольный идентификатор артефакта, указанный в файле pom.xml ) в наш локальный репозиторий. Для получения дополнительной информации о том, как установить локальный JAR с помощью Maven, ознакомьтесь с этой статьей .

Предполагая, что модуль EJB был правильно установлен в наш локальный репозиторий, следующим шагом будет разработка удаленного клиентского приложения, использующего наш TextProcessorBean API.

3. Удаленный EJB-клиент

Мы сохраним бизнес-логику удаленного EJB-клиента предельно простой: во-первых, он выполняет поиск JNDI, чтобы получить прокси TextProcessorBean . После этого он вызывает метод processText() прокси .

3.1. Зависимости Maven

Нам нужно включить следующие артефакты Maven, чтобы клиент EJB работал должным образом:

<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-ejb-client-bom</artifactId>
<version>10.1.0.Final</version>
</dependency>
<dependency>
<groupId>com.beldung.ejbmodule</groupId>
<artifactId>ejbmodule</artifactId>
<version>1.0</version>
</dependency>

Хотя довольно очевидно, почему мы включаем артефакт javaee-api , включение wildfly-ejb-client-bom — нет. Артефакт необходим для выполнения удаленных вызовов EJB в WildFly.

И последнее, но не менее важное: нам нужно сделать предыдущий модуль EJB доступным для клиента, поэтому мы также добавили зависимость ejbmodule .

3.2. Клиентский класс EJB

Учитывая, что EJB-клиент вызывает прокси TextProcessorBean , мы будем очень прагматичны и назовем клиентский класс TextApplication :

public class TextApplication {

public static void main(String[] args) throws NamingException {
TextProcessorRemote textProcessor = EJBFactory
.createTextProcessorBeanFromJNDI("ejb:");
System.out.print(textProcessor.processText("sample text"));
}

private static class EJBFactory {

private static TextProcessorRemote createTextProcessorBeanFromJNDI
(String namespace) throws NamingException {
return lookupTextProcessorBean(namespace);
}

private static TextProcessorRemote lookupTextProcessorBean
(String namespace) throws NamingException {
Context ctx = createInitialContext();
String appName = "";
String moduleName = "EJBModule";
String distinctName = "";
String beanName = TextProcessorBean.class.getSimpleName();
String viewClassName = TextProcessorRemote.class.getName();
return (TextProcessorRemote) ctx.lookup(namespace
+ appName + "/" + moduleName
+ "/" + distinctName + "/" + beanName + "!" + viewClassName);
}

private static Context createInitialContext() throws NamingException {
Properties jndiProperties = new Properties();
jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jboss.naming.remote.client.InitialContextFactory");
jndiProperties.put(Context.URL_PKG_PREFIXES,
"org.jboss.ejb.client.naming");
jndiProperties.put(Context.PROVIDER_URL,
"http-remoting://localhost:8080");
jndiProperties.put("jboss.naming.client.ejb.context", true);
return new InitialContext(jndiProperties);
}
}
}

Проще говоря, все, что делает класс TextApplication , — это извлекает прокси-компонент bean-компонента и вызывает его метод processText() с образцом строки.

Фактический поиск выполняется вложенным классом EJBFactory , который сначала создает экземпляр JNDI InitialContext , затем передает необходимые параметры JNDI в конструктор и, наконец, использует его для поиска прокси-компонента. ``

Обратите внимание, что поиск выполняется с использованием проприетарного пространства имен WildFly «ejb:». Это оптимизирует процесс поиска, поскольку клиент откладывает подключение к серверу до тех пор, пока прокси-сервер не будет явно вызван.

Стоит также отметить, что можно искать прокси-сервер bean-компонента, вообще не прибегая к пространству имен «ejb». Однако мы упустим все дополнительные преимущества отложенных сетевых подключений, что сделает клиент намного менее производительным .

3.3. Настройка контекста EJB

Клиент должен знать, с каким хостом и портом установить соединение для выполнения поиска компонента. В этом случае клиенту требуется настроить проприетарный EJB-контекст WildFly, который определяется файлом jboss-ejb-client.properties , размещенным в его пути к классам, обычно в папке src/main/resources :

endpoint.name=client-endpoint
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false
remote.connections=default
remote.connection.default.host=127.0.0.1
remote.connection.default.port=8080
remote.connection.default.connect.options.org.xnio.Options
.SASL_POLICY_NOANONYMOUS=false
remote.connection.default.username=myusername
remote.connection.default.password=mypassword

Этот файл говорит сам за себя, поскольку он предоставляет все параметры, необходимые для установления соединения с WildFly, включая количество удаленных подключений по умолчанию, хост и порт по умолчанию, а также учетные данные пользователя. В этом случае соединение не шифруется, но может быть при включенном SSL.

Последнее, что нужно учитывать, это то, что если соединение требует аутентификации, необходимо добавить пользователя в WildFly через утилиту add-user.sh/add-user.bat .

4. Вывод

Выполнение поиска EJB в WildFly является простым, если мы строго придерживаемся описанного процесса.

Как обычно, все примеры, включенные в эту статью, доступны на GitHub здесь и здесь .