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

Руководство по интеграции для Spring и EJB

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

1. Обзор

В этой статье мы покажем, как интегрировать Spring и удаленные Enterprise Java Beans (EJB) .

Для этого мы создадим несколько EJB и необходимые удаленные интерфейсы, а затем запустим их внутри JEE-контейнера. После этого мы запустим наше приложение Spring и, используя удаленные интерфейсы, создадим экземпляры наших компонентов, чтобы они могли выполнять удаленные вызовы.

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

2. Настройка EJB

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

2.1. Удаленные интерфейсы EJB

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

Начнем с их интерфейсов:

@Remote
public interface HelloStatefulWorld {
int howManyTimes();
String getHelloWorld();
}
@Remote
public interface HelloStatelessWorld {
String getHelloWorld();
}

2.2. EJB-реализация

Теперь давайте реализуем наши удаленные интерфейсы EJB:

@Stateful(name = "HelloStatefulWorld")
public class HelloStatefulWorldBean implements HelloStatefulWorld {

private int howManyTimes = 0;

public int howManyTimes() {
return howManyTimes;
}

public String getHelloWorld() {
howManyTimes++;
return "Hello Stateful World";
}
}
@Stateless(name = "HelloStatelessWorld")
public class HelloStatelessWorldBean implements HelloStatelessWorld {

public String getHelloWorld() {
return "Hello Stateless World!";
}
}

Если bean-компоненты с состоянием и без состояния кажутся вам незнакомыми, эта вводная статья может оказаться полезной.

2.3. EJB-контейнер

Мы можем запустить наш код в любом JEE-контейнере, но из соображений практичности мы будем использовать Wildfly и плагин Cargo Maven, который сделает всю тяжелую работу за нас:

<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.6.1</version>
<configuration>
<container>
<containerId>wildfly10x</containerId>
<zipUrlInstaller>
<url>
http://download.jboss.org/wildfly/10.1.0.Final/wildfly-10.1.0.Final.zip
</url>
</zipUrlInstaller>
</container>
<configuration>
<properties>
<cargo.hostname>127.0.0.1</cargo.hostname>
<cargo.jboss.configuration>standalone-full</cargo.jboss.configuration>
<cargo.jboss.management-http.port>9990</cargo.jboss.management-http.port>
<cargo.servlet.users>testUser:admin1234!</cargo.servlet.users>
</properties>
</configuration>
</configuration>
</plugin>

2.4. Запуск EJB

С их настройкой мы можем запустить контейнер непосредственно из командной строки Maven:

mvn clean package cargo:run -Pwildfly-standalone

Теперь у нас есть рабочий экземпляр Wildfly, на котором размещены наши bean-компоненты. Мы можем подтвердить это строками журнала:

java:global/ejb-remote-for-spring/HelloStatefulWorld!com.foreach.ejb.tutorial.HelloStatefulWorld
java:app/ejb-remote-for-spring/HelloStatefulWorld!com.foreach.ejb.tutorial.HelloStatefulWorld
java:module/HelloStatefulWorld!com.foreach.ejb.tutorial.HelloStatefulWorld
java:jboss/exported/ejb-remote-for-spring/HelloStatefulWorld!com.foreach.ejb.tutorial.HelloStatefulWorld
java:global/ejb-remote-for-spring/HelloStatefulWorld
java:app/ejb-remote-for-spring/HelloStatefulWorld
java:module/HelloStatefulWorld
java:global/ejb-remote-for-spring/HelloStatelessWorld!com.foreach.ejb.tutorial.HelloStatelessWorld
java:app/ejb-remote-for-spring/HelloStatelessWorld!com.foreach.ejb.tutorial.HelloStatelessWorld
java:module/HelloStatelessWorld!com.foreach.ejb.tutorial.HelloStatelessWorld
java:jboss/exported/ejb-remote-for-spring/HelloStatelessWorld!com.foreach.ejb.tutorial.HelloStatelessWorld
java:global/ejb-remote-for-spring/HelloStatelessWorld
java:app/ejb-remote-for-spring/HelloStatelessWorld
java:module/HelloStatelessWorld

3. Настройка пружины

Теперь, когда наш JEE-контейнер запущен и запущен, а наши EJB развернуты, мы можем запустить наше приложение Spring. Мы будем использовать spring-boot-web , чтобы упростить тестирование вручную, но это не обязательно для удаленного вызова.

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

Чтобы иметь возможность подключаться к удаленным EJB, нам понадобится клиентская библиотека EJB Wildfly и наш удаленный интерфейс:

<dependency>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-ejb-client-bom</artifactId>
<version>10.1.0.Final</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.foreach.spring.ejb</groupId>
<artifactId>ejb-remote-for-spring</artifactId>
<version>1.0.1</version>
<type>ejb</type>
</dependency>

Последнюю версию wildfly-ejb-client-bom можно найти здесь .

3.2. Контекст стратегии именования

С этими зависимостями в пути к классам мы можем создать экземпляр javax.naming.Context для поиска наших удаленных bean-компонентов . Мы создадим это как Spring Bean, чтобы мы могли автоматически подключать его, когда нам это нужно:

@Bean   
public Context context() throws NamingException {
Properties jndiProps = new Properties();
jndiProps.put("java.naming.factory.initial",
"org.jboss.naming.remote.client.InitialContextFactory");
jndiProps.put("jboss.naming.client.ejb.context", true);
jndiProps.put("java.naming.provider.url",
"http-remoting://localhost:8080");
return new InitialContext(jndiProps);
}

Свойства необходимы для информирования как удаленного URL , так и контекста стратегии именования .

3.3. Шаблон JNDI

Прежде чем мы сможем связать наши удаленные bean-компоненты внутри контейнера Spring, нам нужно знать, как к ним добраться. Для этого мы будем использовать их привязки JNDI. Давайте посмотрим стандартный шаблон для этих привязок:

${appName}/${moduleName}/${distinctName}/${beanName}!${viewClassName}

Имейте в виду, что, поскольку мы развернули простую банку вместо уха и не указали имя явно , у нас нет appName и `` DifferentName . Дополнительные подробности можно найти в нашей статье EJB Intro на случай, если что-то покажется странным.

Мы будем использовать этот шаблон для привязки наших удаленных bean-компонентов к нашим Spring.

3.4. Создаем нашу весеннюю фасоль

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

Мы увидим, что эта информация используется сейчас:

@Bean
public HelloStatelessWorld helloStatelessWorld(Context context)
throws NamingException {

return (HelloStatelessWorld)
context.lookup(this.getFullName(HelloStatelessWorld.class));
}
@Bean
public HelloStatefulWorld helloStatefulWorld(Context context)
throws NamingException {

return (HelloStatefulWorld)
context.lookup(this.getFullName(HelloStatefulWorld.class));
}
private String getFullName(Class classType) {
String moduleName = "ejb-remote-for-spring/";
String beanName = classType.getSimpleName();
String viewClassName = classType.getName();
return moduleName + beanName + "!" + viewClassName;
}

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

Имейте в виду, что поиск метода из Context вызовет исключение NamingException , если он не найдет требуемый компонент.

4. Интеграция

Когда все на месте, мы можем внедрить наши bean-компоненты в контроллер , чтобы проверить правильность подключения:

@RestController
public class HomeEndpoint {

// ...

@GetMapping("/stateless")
public String getStateless() {
return helloStatelessWorld.getHelloWorld();
}

@GetMapping("/stateful")
public String getStateful() {
return helloStatefulWorld.getHelloWorld()
+ " called " + helloStatefulWorld.howManyTimes() + " times";
}
}

Давайте запустим наш сервер Spring и проверим некоторые журналы. Мы увидим следующую строку, говорящую о том, что все в порядке:

EJBCLIENT000013: Successful version handshake completed

Теперь давайте проверим наш bean-компонент без сохранения состояния. Мы можем попробовать некоторые команды curl , чтобы убедиться, что они работают должным образом:

curl http://localhost:8081/stateless
Hello Stateless World!

И давайте проверим наш stateful:

curl http://localhost:8081/stateful
Hello Stateful World called 1 times

curl http://localhost:8081/stateful
Hello Stateful World called 2 times

5. Вывод

В этой статье мы узнали, как интегрировать Spring в EJB и выполнять удаленные вызовы контейнера JEE. Мы создали два удаленных интерфейса EJB и смогли прозрачно вызывать те из них, которые используют Spring Beans.

Несмотря на то, что Spring получил широкое распространение, EJB по-прежнему популярны в корпоративных средах, и в этом кратком примере мы показали, что можно использовать как распределенные преимущества Jakarta EE, так и простоту использования приложений Spring.

Как всегда, код можно найти на GitHub .