Guida all'integrazione per Spring e EJB

1. Panoramica

In questo articolo, mostreremo come integrare Spring ed Enterprise Java Beans (EJB) remoti .

Per fare ciò, creeremo alcuni EJB e le interfacce remote necessarie, quindi li eseguiremo all'interno di un contenitore JEE. Dopodiché, avvieremo la nostra applicazione Spring e, utilizzando le interfacce remote, istanzeremo i nostri bean in modo che possano eseguire chiamate remote.

In caso di dubbi su cosa siano o come funzionano gli EJB, abbiamo già pubblicato un articolo introduttivo sull'argomento qui.

2. Configurazione EJB

Avremo bisogno di creare le nostre interfacce remote e le nostre implementazioni EJB. Per renderli utilizzabili, avremo anche bisogno di un contenitore per contenere e gestire i fagioli.

2.1. Interfacce remote EJB

Iniziamo definendo due bean molto semplici: uno senza stato e uno con stato.

Inizieremo con le loro interfacce:

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

2.2. Implementazione EJB

Ora implementiamo le nostre interfacce EJB remote:

@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!"; } } 

Se i bean con stato e senza stato suonano poco familiari, questo articolo introduttivo potrebbe tornare utile.

2.3. Contenitore EJB

Possiamo eseguire il nostro codice in qualsiasi contenitore JEE, ma per motivi di praticità, useremo Wildfly e il plug-in Maven cargo per fare il lavoro pesante per noi:

 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. Esecuzione degli EJB

Con questi configurati, possiamo eseguire il contenitore direttamente dalla riga di comando di Maven:

mvn clean package cargo:run -Pwildfly-standalone

Ora abbiamo un'istanza funzionante di Wildfly che ospita i nostri bean. Possiamo confermarlo dalle righe di registro:

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. Spring Setup

Ora che abbiamo il nostro contenitore JEE attivo e funzionante e i nostri EJB distribuiti, possiamo avviare la nostra applicazione Spring. Useremo spring-boot-web per semplificare il test manuale, ma non è obbligatorio per la chiamata remota.

3.1. Dipendenze di Maven

Per poterci connettere agli EJB remoti, avremo bisogno della libreria Wildfly EJB Client e della nostra interfaccia remota:

 org.wildfly wildfly-ejb-client-bom 10.1.0.Final pom   com.baeldung.spring.ejb ejb-remote-for-spring 1.0.1 ejb 

L'ultima versione di wildfly-ejb-client-bom può essere trovata qui.

3.2. Contesto della strategia di denominazione

Con queste dipendenze nel classpath, possiamo istanziare un javax.naming.Context per eseguire la ricerca dei nostri bean remoti . Lo creeremo come Spring Bean in modo che possiamo autowire quando ne abbiamo bisogno:

@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); }

Le proprietà sono necessarie per informare sia l' URL remoto che il contesto della strategia di denominazione .

3.3. Modello JNDI

Prima di poter collegare i nostri bean remoti all'interno del contenitore Spring, dobbiamo sapere come raggiungerli. Per questo, useremo le loro associazioni JNDI. Vediamo il modello standard per queste associazioni:

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

Tenete a mente che, da quando abbiamo implementato un semplice vaso invece di un orecchio e non in modo esplicito impostare un nome, non abbiamo un appName e distinctName . Ci sono maggiori dettagli nel nostro articolo introduttivo su EJB nel caso qualcosa sembri strano.

Useremo questo modello per associare i nostri bean remoti a quelli primaverili.

3.4. Costruire i nostri fagioli primaverili

Per raggiungere i nostri EJB, utilizzeremo il suddetto JNDI. Ricordi le righe di log che abbiamo utilizzato per verificare se i nostri bean enterprise sono stati distribuiti?

Vedremo ora queste informazioni in uso:

@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; }

Dobbiamo stare molto attenti al collegamento completo JNDI corretto , altrimenti il ​​contesto non sarà in grado di raggiungere il bean remoto e creare l'infrastruttura sottostante necessaria.

Tieni presente che la ricerca del metodo da Context genererà una NamingException nel caso in cui non trovi il bean che stai richiedendo.

4. Integrazione

Con tutto a posto, possiamo iniettare i nostri fagioli in un controller , in modo da poter verificare se il cablaggio è corretto:

@RestController public class HomeEndpoint { // ... @GetMapping("/stateless") public String getStateless() { return helloStatelessWorld.getHelloWorld(); } @GetMapping("/stateful") public String getStateful() { return helloStatefulWorld.getHelloWorld() + " called " + helloStatefulWorld.howManyTimes() + " times"; } }

Avviamo il nostro server Spring e controlliamo alcuni log. Vedremo la seguente riga, che indica che è tutto OK:

EJBCLIENT000013: Successful version handshake completed

Ora, testiamo il nostro fagiolo senza stato. Possiamo provare alcuni comandi curl per verificare che funzionino come previsto:

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

E controlliamo il nostro stato:

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

5. conclusione

In questo articolo abbiamo imparato come integrare Spring in EJB ed effettuare chiamate remote al contenitore JEE. Abbiamo creato due interfacce EJB remote e siamo stati in grado di chiamare quelle che utilizzano Spring Beans in modo trasparente.

Anche se Spring è ampiamente adottato, gli EJB sono ancora popolari negli ambienti aziendali e, in questo rapido esempio, abbiamo dimostrato che è possibile utilizzare sia i vantaggi distribuiti di Jakarta EE sia la facilità d'uso delle applicazioni Spring.

Come sempre, il codice può essere trovato su GitHub.