1. Обзор
В этой статье мы покажем, как интегрировать Spring и удаленные корпоративные Java-компоненты (EJB) .
Для этого мы создадим несколько EJB и необходимые удаленные интерфейсы, а затем запустим их в контейнере JEE. После этого мы запустим наше приложение Spring и, используя удаленные интерфейсы, создадим экземпляры наших компонентов, чтобы они могли выполнять удаленные вызовы.
Если есть какие-либо сомнения относительно того, что такое EJB или как они работают, мы уже опубликовали вступительную статью на эту тему здесь .
2. Настройка EJB
Нам нужно будет создать наши удаленные интерфейсы и наши реализации EJB. Чтобы сделать их пригодными для использования, нам также понадобится контейнер для хранения бобов и управления ими.
2.1. Удаленные интерфейсы EJB
Давайте начнем с определения двух очень простых компонентов — одного без гражданства и одного с сохранением состояния.
Начнем с их интерфейсов:
@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!"; } }
Если бобы с состоянием и без состояния звучат незнакомо, эта вводная статья может пригодиться.
2.3. Контейнер EJB
Мы можем запустить наш код в любом контейнере JEE, но для практических целей мы будем использовать Wildfly и плагин cargo Maven, чтобы сделать тяжелую работу за нас:
org.codehaus.cargo cargo-maven2-plugin 1.6.1 wildfly10x http://download.jboss.org/wildfly/10.1.0.Final/wildfly-10.1.0.Final.zip 127.0.0.1 standalone-full 9990 testUser:admin1234!
2.4. Запуск EJBs
Если они настроены, мы можем запустить контейнер непосредственно из командной строки Maven:
mvn clean package cargo:run -Pwildfly-standalone
Теперь у нас есть рабочий экземпляр Wildfly, размещающий наши бобы. Мы можем подтвердить это строками журнала:
java:global/ejb-remote-for-spring/HelloStatefulWorld!com.baeldung.ejb.tutorial.HelloStatefulWorld java:app/ejb-remote-for-spring/HelloStatefulWorld!com.baeldung.ejb.tutorial.HelloStatefulWorld java:module/HelloStatefulWorld!com.baeldung.ejb.tutorial.HelloStatefulWorld java:jboss/exported/ejb-remote-for-spring/HelloStatefulWorld!com.baeldung.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.baeldung.ejb.tutorial.HelloStatelessWorld java:app/ejb-remote-for-spring/HelloStatelessWorld!com.baeldung.ejb.tutorial.HelloStatelessWorld java:module/HelloStatelessWorld!com.baeldung.ejb.tutorial.HelloStatelessWorld java:jboss/exported/ejb-remote-for-spring/HelloStatelessWorld!com.baeldung.ejb.tutorial.HelloStatelessWorld java:global/ejb-remote-for-spring/HelloStatelessWorld java:app/ejb-remote-for-spring/HelloStatelessWorld java:module/HelloStatelessWorld
3. Установка пружины
Теперь, когда наш контейнер JEE запущен и запущен, а наши EJBS развернуты, мы можем запустить наше приложение Spring. Мы будем использовать spring-boot-web , чтобы упростить тестирование вручную, но это не обязательно для удаленного вызова.
3.1. Зависимости Maven
Чтобы иметь возможность подключиться к удаленным EJBS, нам понадобится клиент Wildfly EJB библиотека и наш удаленный интерфейс:
org.wildfly wildfly-ejb-client-bom 10.1.0.Final pom com.baeldung.spring.ejb ejb-remote-for-spring 1.0.1 ejb
Последнюю версию wildfly-ejb-client-bom можно найти здесь .
3.2. Контекст Стратегии именования
С помощью этих зависимостей в пути к классу мы можем создать экземпляр javax.naming.Контекст для поиска наших удаленных бобов . Мы создадим это как весенний боб, чтобы мы могли автоматически подключать его, когда нам это нужно:
@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
Прежде чем мы сможем подключить наши удаленные бобы к пружинному контейнеру, нам нужно знать, как до них добраться. Для этого мы будем использовать их привязки JNDI. Давайте посмотрим стандартный шаблон для этих привязок:
${appName}/${moduleName}/${distinctName}/${beanName}!${viewClassName}
Имейте в виду, что, поскольку мы развернули простой jar вместо ear и явно не настроили имя, у нас нет AppName и distinctName . Более подробная информация содержится в нашей статье EJB Intro на случай, если что-то покажется странным.
Мы будем использовать этот шаблон, чтобы привязать наши удаленные бобы к нашим весенним.
3.4. Создание Наших Весенних Бобов
Чтобы добраться до наших EJBS, мы будем использовать вышеупомянутый 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 и создать необходимую базовую инфраструктуру.
Имейте в виду, что метод lookup from Context вызовет исключение NamingException в случае, если он не найдет нужный вам компонент.
4. Интеграция
Имея все на месте, мы можем ввести наши бобы в контроллер , чтобы проверить, правильна ли проводка:
@RestController public class HomeEndpoint { // ... @GetMapping("/stateless") public String getStateless() { return helloStatelessWorld.getHelloWorld(); } @GetMapping("/stateful") public String getStateful() { return helloStatefulWorld.getHelloWorld() + " called " + helloStatefulWorld.howManyTimes() + " times"; } }
Давайте запустим наш весенний сервер и проверим некоторые журналы. Мы увидим следующую строку, указывающую на то, что все в порядке:
EJBCLIENT000013: Successful version handshake completed
Теперь давайте проверим наш боб без гражданства. Мы можем попробовать некоторые команды curl , чтобы убедиться, что они работают должным образом:
curl http://localhost:8081/stateless Hello Stateless World!
И давайте проверим состояние:
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 .