Einführung in die EJB JNDI-Suche auf WildFly Application Server

1. Übersicht

Enterprise Java Beans (EJB) sind der Kernbestandteil der Java EE-Spezifikation, um die Entwicklung verteilter Anwendungen auf Unternehmensebene zu vereinfachen. Der Lebenszyklus von EJBs wird von einem Anwendungsserver wie JBoss WildFly oder Oracle GlassFish verwaltet.

EJBs bieten ein robustes Programmiermodell, das die Implementierung von Softwaremodulen auf Unternehmensebene erleichtert, da es Sache des Anwendungsservers ist, nicht geschäftslogikbezogene Probleme wie Transaktionsbehandlung, Verwaltung des Komponentenlebenszyklus oder Abhängigkeitsinjektion zu behandeln.

Darüber hinaus haben wir bereits zwei Artikel veröffentlicht, die die Grundkonzepte von EJB behandeln. Schauen Sie sich diese hier und hier an.

In diesem Tutorial zeigen wir, wie Sie ein grundlegendes EJB-Modul in WildFly implementieren und einen EJB von einem Remote-Client über eine JNDI aufrufen.

2. Implementierung des EJB-Moduls

Geschäftslogik wird entweder durch eine oder mehrere lokale / Remote-Geschäftsschnittstellen (auch als lokale / Remote-Ansichten bezeichnet) oder direkt über Klassen implementiert, die keine Schnittstelle implementieren (Nicht-Ansichtsschnittstellen).

Es ist erwähnenswert, dass lokale Geschäftsschnittstellen verwendet werden, wenn auf die Bean von Clients zugegriffen werden soll, die sich in derselben Umgebung befinden, dh in derselben EAR- oder WAR-Datei, während Remote-Geschäftsschnittstellen erforderlich sind, wenn auf die Bean aus einer anderen Umgebung zugegriffen wird dh eine andere JVM oder ein anderer Anwendungsserver.

Lassen Sie uns ein grundlegendes EJB-Modul erstellen, das nur aus einer Bean besteht. Die Geschäftslogik der Bean ist unkompliziert und beschränkt sich auf die Konvertierung eines bestimmten Strings in seine Großbuchstabenversion.

2.1. Definieren einer Remote-Geschäftsschnittstelle

Definieren wir zunächst eine einzelne Remote-Geschäftsschnittstelle, die mit der Annotation @Remote versehen ist . Dies ist gemäß der EJB 3.x-Spezifikation obligatorisch, da auf die Bean von einem Remote-Client aus zugegriffen werden soll:

@Remote public interface TextProcessorRemote { String processText(String text); }

2.2. Eine zustandslose Bohne definieren

Als nächstes realisieren wir die Geschäftslogik durch Implementierung der oben genannten Remote-Schnittstelle:

@Stateless public class TextProcessorBean implements TextProcessorRemote { public String processText(String text) { return text.toUpperCase(); } }

Die TextProcessorBean- Klasse ist eine einfache Java-Klasse, die mit der Annotation @Stateless dekoriert ist .

Statuslose Beans behalten per Definition keinen Konversationsstatus mit ihren Clients bei, selbst wenn sie den Instanzstatus für verschiedene Anforderungen beibehalten können. Ihr Gegenstück, Stateful Beans, behält ihren Konversationsstatus bei und ist beispielsweise teurer für die Erstellung für den Anwendungsserver.

Da in diesem Fall die obige Klasse keinen Instanzstatus hat, kann sie zustandslos gemacht werden. Für den Fall, dass es einen Status hat, wäre es überhaupt nicht sinnvoll, ihn für verschiedene Clientanforderungen zu verwenden.

Das Verhalten der Bohne ist deterministisch , das heißt, es hat keine Nebenwirkungen, wie eine gut konzipierte Bohne sein sollte: es dauert nur einen Eingang String und gibt die Groß Version davon.

2.3. Maven-Abhängigkeiten

Als Nächstes müssen wir dem Modul das Javaee-API- Maven-Artefakt hinzufügen , das alle Java EE 7-Spezifikations-APIs bereitstellt, einschließlich der für EJBs erforderlichen:

 javax javaee-api 7.0 provided 

Zu diesem Zeitpunkt ist es uns gelungen, ein grundlegendes und dennoch funktionales EJB-Modul zu erstellen. Um es allen potenziellen Kunden zur Verfügung zu stellen, müssen wir das Artefakt als JAR-Datei in unser lokales Maven-Repository einfügen.

2.4. Installieren des EJB-Moduls im lokalen Repository

Es gibt verschiedene Methoden, um dies zu erreichen. Am einfachsten ist es, die Maven-Lebenszyklus- Clean-Install- Build-Phasen auszuführen :

mvn clean install

Dieser Befehl installiert das EJB-Modul als ejbmodule-1.0.jar ( oder eine beliebige in der Datei pom.xml angegebene Artefakt-ID ) in unserem lokalen Repository. Weitere Informationen zum Installieren einer lokalen JAR mit Maven finden Sie in diesem Artikel.

Unter der Annahme, dass das EJB-Modul korrekt in unserem lokalen Repository installiert wurde, besteht der nächste Schritt darin, eine Remote-Client-Anwendung zu entwickeln, die unsere TextProcessorBean- API verwendet.

3. Remote-EJB-Client

Wir werden die Geschäftslogik des Remote-EJB-Clients äußerst einfach halten: Zunächst wird eine JNDI-Suche durchgeführt, um einen TextProcessorBean- Proxy zu erhalten. Danach wird die processText () -Methode des Proxys aufgerufen .

3.1. Maven-Abhängigkeiten

Wir müssen die folgenden Maven-Artefakte einbeziehen, damit der EJB-Client wie erwartet funktioniert:

 javax javaee-api 7.0 provided   org.wildfly wildfly-ejb-client-bom 10.1.0.Final   com.beldung.ejbmodule ejbmodule 1.0 

Während es ziemlich offensichtlich ist, warum wir das Javaee-API- Artefakt einschließen , ist die Einbeziehung von Wildfly-EJB-Client-Bom nicht der Fall . Das Artefakt wird für die Ausführung von Remote-EJB-Aufrufen in WildFly benötigt.

Last but not least müssen wir dem Client das vorherige EJB-Modul zur Verfügung stellen. Deshalb haben wir auch die ejbmodule- Abhängigkeit hinzugefügt .

3.2. EJB-Client-Klasse

In Anbetracht dessen, dass der EJB-Client einen Proxy von TextProcessorBean aufruft , sind wir sehr pragmatisch und nennen die Clientklasse TextApplication :

public class TextApplication { public static void main(String[] args) throws NamingException { TextProcessorRemote textProcessor = EJBFactory .createTextProcessorBeanFromJNDI("ejb:"); System.out.print(textProcessor.processText("sample text")); } private static class EJBFactory { private static TextProcessorRemote createTextProcessorBeanFromJNDI (String namespace) throws NamingException { return lookupTextProcessorBean(namespace); } private static TextProcessorRemote lookupTextProcessorBean (String namespace) throws NamingException { Context ctx = createInitialContext(); String appName = ""; String moduleName = "EJBModule"; String distinctName = ""; String beanName = TextProcessorBean.class.getSimpleName(); String viewClassName = TextProcessorRemote.class.getName(); return (TextProcessorRemote) ctx.lookup(namespace + appName + "/" + moduleName + "/" + distinctName + "/" + beanName + "!" + viewClassName); } private static Context createInitialContext() throws NamingException { Properties jndiProperties = new Properties(); jndiProperties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory"); jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); jndiProperties.put(Context.PROVIDER_URL, "http-remoting://localhost:8080"); jndiProperties.put("jboss.naming.client.ejb.context", true); return new InitialContext(jndiProperties); } } }

Einfach gesagt, all das die TextApplicationclass does is retrieving the bean proxy and call its processText() method with a sample string.

The actual lookup is performed by the nested class EJBFactory, which first creates a JNDI InitialContext instance, then passes the required JNDI parameters to the constructor, and finally uses it for looking up the bean proxy.

Notice that the lookup is performed by using WildFly’s proprietary “ejb:” namespace. This optimizes the lookup process, as the client defers the connection to the server until the proxy is explicitly invoked.

It’s worth noting as well that it's possible to lookup the bean proxy without resorting to the “ejb” namespace at all. However, we'd be missing all the additional benefits of lazy network connections, thus making the client a lot less performant.

3.3. Setting Up the EJB Context

The client should know what host and port to establish a connection with to perform the bean lookup. To this extent, the client requires setting up the proprietary WildFly EJB context, which is defined with the jboss-ejb-client.properties file placed in its classpath, usually under the src/main/resources folder:

endpoint.name=client-endpoint remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false remote.connections=default remote.connection.default.host=127.0.0.1 remote.connection.default.port=8080 remote.connection.default.connect.options.org.xnio.Options .SASL_POLICY_NOANONYMOUS=false remote.connection.default.username=myusername remote.connection.default.password=mypassword

Die Datei ist ziemlich selbsterklärend, da sie alle Parameter enthält, die zum Herstellen einer Verbindung zu WildFly erforderlich sind, einschließlich der Standardanzahl der Remoteverbindungen, des Standardhosts und -ports sowie der Benutzeranmeldeinformationen. In diesem Fall ist die Verbindung nicht verschlüsselt, dies kann jedoch der Fall sein, wenn SSL aktiviert ist.

Als letztes muss berücksichtigt werden, dass, wenn für die Verbindung eine Authentifizierung erforderlich ist, ein Benutzer über das Dienstprogramm add-user.sh/add-user.bat zu WildFly hinzugefügt werden muss .

4. Fazit

Das Durchführen von EJB-Suchvorgängen auf WildFly ist unkompliziert, solange wir uns strikt an den beschriebenen Prozess halten.

Wie üblich sind alle in diesem Artikel enthaltenen Beispiele hier und hier auf GitHub verfügbar.