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 .