1. Общ преглед
В тази статия ще покажем как да интегрираме Spring и отдалечени Enterprise Java Beans (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 и приставката за товар Maven, за да направим тежкото вдигане за нас:
org.codehaus.cargo cargo-maven2-plugin 1.6.1 wildfly10x //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. Стартиране на EJB
С тези конфигурирани можем да стартираме контейнера директно от командния ред на 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 и разполагаме нашите EJB, можем да стартираме нашето приложение Spring. Ще използваме spring-boot-web, за да улесним ръчното тестване, но не е задължително за отдалеченото повикване.
3.1. Зависимости на Maven
За да можем да се свържем с отдалечените EJB, ще ни трябва клиентската библиотека 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.Context, за да направим търсенето на нашите отдалечени компоненти . Ще създадем това като 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 модел
Преди да можем да свържем нашите отдалечени зърна в контейнера Spring, ще трябва да знаем как да ги достигнем. За това ще използваме техните JNDI обвързвания. Нека видим стандартния модел за тези обвързвания:
${appName}/${moduleName}/${distinctName}/${beanName}!${viewClassName}
Имайте предвид, че, тъй като ние разгърнати прост буркан вместо ухо и не изрично създаде име, ние не разполагат с APPNAME и distinctName . Има повече подробности в нашата статия за EJB Intro, в случай че нещо изглежда странно.
Ще използваме този модел, за да обвържем нашите отдалечени зърна с нашите пролетни.
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. Интеграция
С всичко на място можем да инжектираме зърната си в контролер , за да можем да проверим дали окабеляването е правилно:
@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
Сега, нека тестваме нашия боб без гражданство. Можем да изпробваме някои команди за навиване, за да проверим дали работят както се очаква:
curl //localhost:8081/stateless Hello Stateless World!
И нека проверим нашия държавен:
curl //localhost:8081/stateful Hello Stateful World called 1 times curl //localhost:8081/stateful Hello Stateful World called 2 times
5. Заключение
В тази статия научихме как да интегрираме Spring към EJB и да осъществим отдалечени повиквания към контейнера JEE. Създадохме два отдалечени EJB интерфейса и успяхме да извикаме тези, които използват Spring Beans, по прозрачен начин.
Въпреки че Spring е широко приет, EJB са все още популярни в корпоративна среда и в този бърз пример показахме, че е възможно да се използват както разпределените печалби от Jakarta EE, така и лекотата на използване на Spring приложения.
Както винаги, кодът може да бъде намерен в GitHub.