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

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

1. обзор

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

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

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

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

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

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

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

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

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

Давайте сначала определим один-единственный удаленный бизнес-интерфейс, украшенный аннотацией@Remote. Это обязательно, согласноEJB 3.x specification, поскольку доступ к 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-компонент: он просто принимает входнойString и возвращает его версию в верхнем регистре.

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

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


    javax
    javaee-api
    7.0
    provided

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

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

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

mvn clean install

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

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

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

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

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

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


    javax
    javaee-api
    7.0
    provided


    org.wildfly
    wildfly-ejb-client-bom
    10.1.0.Final


    com.beldung.ejbmodule
    ejbmodule
    1.0

Хотя совершенно очевидно, почему мы включаем артефактjavaee-api, включениеwildfly-ejb-client-bom - нет. The artifact is required for performing remote EJB invocations on 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, который сначала создает экземпляр JNDIInitialContext, затем передает необходимые параметры JNDI конструктору и, наконец, использует его для поиска прокси компонента.

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

Также стоит отметить, что можно выполнять поиск прокси-компонента, вообще не обращаясь к пространству имен «ejb». Однакоwe’d be missing all the additional benefits of lazy network connections, thus making the client a lot less performant.

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

Клиент должен знать, с каким хостом и портом устанавливать соединение, чтобы выполнить поиск компонента. В этом случаеthe client requires setting up the proprietary WildFly EJB context, which is defined with the jboss-ejb-client.properties file помещается в свой путь к классам, обычно в папке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.

Последнее, что нужно учитывать, это то, чтоif the connection requires authentication, it’s necessary to add a user to WildFly via the https://docs.jboss.org/author/display/WFLY8/add-user+utility?sscc=t[_add-user.sh/add-user.bat utility].

4. Заключение

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

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