J2EE 1.4 vereinfacht die Entwicklung von Webdiensten

Zum Abschluss seiner Präsentation der J2EE-Webdienste (Java 2 Platform, Enterprise Edition) auf der JavaOne im letzten Jahr bemerkte der IBM-Architekt Jim Knutson: "Jeder Webdienst benötigt einen Ort, an dem er ein Dienst sein kann." Anschließend schlug er vor, dass der idealste Ort für einen Webdienst die J2EE-Infrastruktur sei. Etwas mehr als ein Jahr später steht die endgültige Veröffentlichung von J2EE 1.4 unmittelbar bevor, und das wichtigste Versprechen besteht darin, die Vision der J2EE-Webdienste umzusetzen.

Die Webdienstfunktionen in J2EE 1.4 richten sich sowohl an die Server- als auch an die Clientseite von Webdiensten. Die Funktionen erweitern J2EE, damit vorhandene serverseitige Java-Unternehmenskomponenten zu Webdiensten werden können, und legen fest, wie ein J2EE-Clientcontainer Webdienste aufrufen kann. Die Technologien für beide Ziele existieren seit einiger Zeit, und die neuen J2EE-Spezifikationen basieren auf diesen vorhandenen APIs für die Unterstützung von Webdiensten. Die neuen Spezifikationen ergänzen die vorhandenen Technologien um eine Reihe von Interoperabilitätsanforderungen sowie ein Programmier- und Bereitstellungsmodell für die Integration von Webdiensten.

Es gibt zwei Spezifikationen, die diese hinzugefügten Funktionen explizit beschreiben: Java Specification Request 151, das Dach JSR für J2EE 1.4 und JSR 109, Web Services für J2EE. Zum Zeitpunkt dieses Schreibens hat JSR 109 seine letzte Phase im JCP (Java Community Process) erreicht, während sich JSR 151 in der letzten Abstimmungsphase befindet. Darüber hinaus hat das JCP die endgültige Version von JSR 101, Java-APIs für XML-basierten Remote Procedure Call (JAX-RPC), geändert, um die Interoperationsanforderungen für J2EE 1.4 zu unterstützen.

J2EE 1.3-Level-Anwendungsserver können auch viele der von diesen JSRs vorgeschriebenen Funktionen implementieren. In der Tat unterstützen viele Anbieter von Anwendungsservern seit einiger Zeit verschiedene Funktionen zur Entwicklung und Bereitstellung von Webdiensten in ihren vorhandenen Produkten. Die JSRs 109 und 151 kodifizieren einige bestehende Praktiken und beschreiben neue Mechanismen in der Hoffnung, ein universelles Integrationsmodell für J2EE-Webdienste zu schaffen. Anwendungsserver der nächsten Generation werden wahrscheinlich diesem einheitlichen, standardisierten Modell folgen.

Nach einer kurzen Übersicht über die neuen J2EE-Funktionen im Zusammenhang mit Webdiensten werden in diesem Artikel die neuen Client- und Server-Programmiermodelle beschrieben, einschließlich der neuen J2EE-Bereitstellungs- und Dienstverwaltungsrollen im Zusammenhang mit der Unterstützung von Webdiensten.

Webdienstbezogene J2EE-Erweiterungen

Die vielleicht wichtigsten und folgenreichsten Ergänzungen zu J2EE sind die neuen Interoperationsanforderungen. Die Anforderungen schreiben die Unterstützung von SOAP (Simple Object Access Protocol) 1.1 in der J2EE-Präsentationsschicht vor, um den Austausch von XML-Nachrichten zu erleichtern. J2EE 1.4-kompatible Container müssen auch das Basisprofil WS-I (Web Services Interoperability Consortium) unterstützen. Da der Austausch von XML-Nachrichten in J2EE von JAX-RPC abhängt, schreiben die JAX-RPC-Spezifikationen jetzt auch die Unterstützung des WS-I-Basisprofils vor.

Das Ergebnis ist, dass eine J2EE 1.4-basierte Anwendung als Webdienst aufgerufen werden kann, selbst von Anwendungen, die nicht in der Programmiersprache Java geschrieben sind. Während dies für J2EE ein Evolutionsschritt ist, da die Plattform seit langem nicht auf Java basierende Systeme umfasst, ist dies möglicherweise der direkteste Weg, um die Interaktion mit Windows-basierten Technologien zu erleichtern, die auf .Net basieren.

Der Client eines J2EE-basierten Dienstes muss nicht wissen, wie ein Dienst implementiert wird. Dieser Client kann den Dienst vielmehr verwenden, indem er sich vollständig auf die WSDL-Definition (Web Services Description Language) des Dienstes verlässt. (In früheren JavaWorld- Webdienstspalten wird erläutert, wie Dienste anhand ihrer WSDL-Definitionen ermittelt und WSDL-Definitionen erstellt und verwendet werden. Links finden Sie unter Ressourcen.) In den J2EE-Spezifikationen wird die genaue Funktionsweise einer solchen Interaktion nicht beschrieben. J2EE 1.4 ' Die Akzeptanz des WS-I-Basisprofils, dem Microsoft ebenfalls folgen will, wird wahrscheinlich die Interaktion mit J2EE-.Net allgemein machen.

Um den Zugriff auf WSDL-Definitionen zu erleichtern, bietet J2EE 1.4 Unterstützung für den JAXR-Standard (Java API for XML Registries). Die JAXR-Bibliotheken sind jetzt ein erforderlicher Bestandteil des J2EE-Anwendungsclients, der EJB (Enterprise JavaBeans) und der Webcontainer (jedoch nicht des Applet-Containers). Da WS-I Basic Profile die Unterstützung von UDDI 2.0 (Universal Description, Discovery and Integration) 2.0 vorschreibt, können J2EE-Clients sowie EJB-Komponenten und -Servlets mit öffentlichen Webdienstregistern interagieren. ("Webdienste nehmen Float mit JAXR" ( JavaWorld, Mai 2002) bietet ein Tutorial zu JAXR.) Abbildung 1 zeigt die zusätzlichen von J2EE 1.4 unterstützten Bibliotheken für Webdienste.

In der Tat ist J2EE der Ansicht, dass ein Webdienst eine Implementierung einer oder mehrerer Schnittstellen ist, die durch ein WSDL-Dokument definiert sind. Die in WSDL beschriebenen Vorgänge werden zuerst Java-Methoden gemäß den WSDL-Java-Zuordnungsregeln der JAX-RPC-Spezifikation zugeordnet. Sobald eine Java-Schnittstelle definiert ist, die einer WSDL-Datei entspricht, können Sie die Methoden dieser Schnittstelle auf zwei Arten implementieren: als zustandslose Session-Bean, die im EJB-Container ausgeführt wird, oder als Java-Klasse, die im J2EE-Servlet-Container ausgeführt wird. Schließlich sorgen Sie dafür, dass der jeweilige Container auf eingehende SOAP-Anforderungen wartet und diese Anforderungen der jeweiligen Implementierung (EJB oder Servlet) zuordnet. Um eingehende SOAP-Aufrufe zu verarbeiten, schreibt J2EE 1.4 die JAX-RPC-Laufzeit als zusätzlichen J2EE-Containerdienst vor.

In Übereinstimmung mit der J2EE-Architektur vermittelt der Container einer Dienstimplementierung den Zugriff auf einen Webdienst: Wenn Sie entweder eine EJB-Komponente oder ein Servlet als J2EE-Webdienst verfügbar machen, können die Clients Ihres Dienstes diesen Dienst nur indirekt über den Container aufrufen. Dadurch kann eine Service-Implementierung von der Sicherheit des Containers, dem Thread-Management und sogar von Garantien für die Servicequalität profitieren. Darüber hinaus können Sie in Containern wichtige Webdienstentscheidungen treffen, z. B. Sicherheitsbeschränkungen, während der Bereitstellung. Schließlich macht das container-basierte Modell von J2EE die Bereitstellung von Webdiensten portabel: Sie können einen Java-basierten Webdienst mit jedem J2EE-Tool entwickeln und erwarten, dass dieser Dienst in jeder anderen kompatiblen Container-Implementierung ausgeführt wird.

Ein Webdienst-Client hingegen weiß nicht, dass ein Webdienst-Container vorhanden ist. Stattdessen sieht der Client einen Port, der eine Netzwerkendpunktinstanz eines Webdienstes darstellt. Dieser Endpunkt folgt dem SEI-Modell ( JAX-RPC Service Endpoint Interface ) und bietet eine Implementierung der Schnittstelle des Dienstes. Ein Client betrachtet jeden J2EE-Webdienst als eine Kombination aus SEI und Port. Ein einzelner J2EE-Container kann viele solcher Kombinationen enthalten, wie in Abbildung 2 dargestellt. Jede SEI / Port-Kombination ist eine Instanz eines Webdienstes.

Beachten Sie, dass der Client in dieser Architektur entweder ein J2EE-Client sein kann, der im J2EE-Client-Container ausgeführt wird, oder ein Nicht-J2EE-Client. Jeder WS-I Basic Profile-kompatible Client kann einen J2EE-Webdienst verwenden, aber jeder Client kann unterschiedlichen Programmiermodellen folgen. Die J2EE-Webdienstspezifikation beschreibt ein Programmiermodell für Clients, die im J2EE-Anwendungsclientcontainer ausgeführt werden, und ein anderes Modell - das Serverprogrammiermodell - für Webdienstimplementierungen, die in den EJB- oder Servletcontainern ausgeführt werden.

Das Programmiermodell für den J2EE-Webdienst-Client

Der Kern des Webdienst-Client-Programmiermodells besteht darin, die Verwendung der in den JSRs 67 (Java-APIs für XML-Messaging, JAXM), 93 (JAXR) und 101 (JAX-RPC) definierten APIs zu optimieren und ein umfassendes Framework für bereitzustellen Verwenden dieser APIs zusammen im J2EE-Clientcontainer.

In Übereinstimmung mit dem Programmiermodell des J2EE-Clients ist ein Webdienstclient remote und bietet lokale / Remote-Transparenz. Der Webdienst-Portanbieter und der Container, in dem der Port ausgeführt wird, definieren, wie ein Client einen Webdienst sieht. Der Client greift immer auf den Port zu und erhält niemals einen direkten Verweis auf die Implementierung eines Webdienstes. Ein J2EE-Webdienst-Client weiß nicht, wie ein Port funktioniert, und muss sich nur mit den von einem Port definierten Methoden befassen. Diese Methoden bilden die öffentliche Schnittstelle eines Webdienstes. Darüber hinaus muss ein Client den Zugriff auf einen Webdienstport über Dienstaufrufe hinweg als zustandslos betrachten. Für den Client fehlt einem Port eine eindeutige Identität. Ein Client kann nicht feststellen, ob er über Dienstaufrufe hinweg mit identischen Ports kommuniziert.

Der Client erhält Zugriff auf einen Port basierend auf der Serviceschnittstelle des Ports. J2EE-Webdienste basieren auf JAX-RPC, um die Beziehung zwischen einem Port und seiner Dienstschnittstelle zu definieren. JAX-RPC erstellt diese Beziehung basierend auf WSDL-Verarbeitungsregeln. Somit bestimmt die WSDL-Definition des Webdienstes letztendlich das Verhalten des Ports. Basierend auf der JAX-RPC-Definition kann die Dienstschnittstelle entweder eine generische Schnittstelle sein, die die Schnittstelle direkt implementiert javax.xml.rpc.Service, oder ein "generierter Dienst", der ein Subtyp dieser Schnittstelle ist. Der letztere Schnittstellentyp ist spezifisch für den Typ eines Webdienstes.

Im J2EE-Programmiermodell erhält der Client Serviceüber eine JNDI-Suchoperation (Java Naming and Directory Interface) einen Verweis auf das Objekt eines Webdienstes . Die JNDI-Suche erfolgt über einen logischen Namen oder eine Dienstreferenz für den Webdienst. Wie bei allen verzeichnisbasierten Ressourcen muss ein Client in seinem Bereitstellungsdeskriptor angeben, welche Ressourcen er benötigt (dazu später mehr).

In der Java Web Services-Spezifikation (JSR 109) wird empfohlen, alle Web Services unter dem JNDI- serviceUnterkontext zu subsumieren . Der Clientcontainer bindet die durch diese Referenz beschriebene Serviceschnittstelle im java:comp/envNamenskontext der Clientumgebung. Durch Deklarieren einer Dienstreferenz im Bereitstellungsdeskriptor des Clients stellt der Clientcontainer sicher, dass der Dienst, auf den verwiesen wird, in JNDI-fähigen Ressourcen verfügbar ist. Der folgende Codeausschnitt zeigt, wie Sie über die JNDI-Suche einen Verweis auf einen J2EE-basierten Webdienst erhalten:

InitialContext ctx = neuer InitialContext (); Service myService = (Service) ctx.lookup ("java: comp / env / services / MyWebService");

Der obige Code erhält ein generisches Dienstobjekt: ein Objekt ohne einen bestimmten Typ. Auf einen von JAX-RPC generierten Dienst wird auf dieselbe Weise zugegriffen. Diesmal wird der Dienst in den Schnittstellentyp des jeweiligen Webdienstes umgewandelt:

InitialContext ctx = neuer InitialContext (); MyWebService myService = (MyWebService) ctx.lookup ("java: / comp / env / services / MyWebService");

Beachten Sie, dass dieser Code davon ausgeht, dass die MyWebServiceReferenz an ein Objekt gebunden ist, das die MyWebServiceSchnittstelle implementiert . Da die Servicebindung zur Bereitstellungszeit eines Webdienstes erleichtert wird, wird von J2EE-Tools erwartet, dass sie diese Konsistenz sicherstellen. Alle J2EE 1.4-kompatiblen Anwendungsserver müssen die JNDI-basierte Dienstsuche unterstützen.

Sobald ein Client das ServiceObjekt eines Webdienstes erhalten hat , kann er dieses Objekt verwenden, um eine javax.xml.rpc.CallInstanz abzurufen , die den eigentlichen Dienstaufruf ausführt. Der Client hat drei Optionen, um eine zu erhalten Call: über einen Stub, einen dynamischen Service-Proxy oder eine DII (Dynamic Invocation Interface). In diesem Artikel werde ich nicht auf die Unterschiede zwischen diesen Methoden eingehen, da unabhängig davon, wie eine Callerstellt wird, diese Calldirekt auf den Port des Dienstes verweist - das einzige Objekt, das dem Client beim Aufrufen des Webdienstes bekannt sein muss. Alle J2EE 1.4-kompatiblen Container müssen die ServiceSchnittstellenmethoden unterstützen und ermöglichen es einem Client, über einen Verweis auf ein CallObjekt für einen Webdienst und auf den Port dieses Dienstes abzurufen Call.

Beachten Sie, dass ein Client im Gegensatz zur Verwendung von JAX-RPC außerhalb von J2EE die JAX-RPC- ServiceFactoryKlasse nicht verwenden sollte , um einen neuen Dienst zu erhalten. Stattdessen sollte der Client Servicevon einer JNDI-basierten Quelle aus Zugriff auf die erhalten , da der Verweis auf einen von JNDI abgerufenen Dienst alle Einstellungen und Konfigurationen enthält, die zum Aufrufen der jeweiligen Dienstinstanz erforderlich sind. Aus Sicht eines Clients ist dieser Unterschied etwas analog dazu, wie ein J2EE-Client einen JDBC DataSourceüber die JNDI-Schnittstelle abruft , um auf eine Datenbank zuzugreifen, anstatt eine JDBC- ConnectionInstanz manuell zu konfigurieren .

Mit diesem CallObjekt folgt der Client der JAX-RPC-Semantik des Remoteprozeduraufrufs. Beispielsweise kann der Client die invoke()Methode verwenden, Callum mit dem Webdienst zu interagieren. (Ein Beispiel für einen Dienstaufruf im JAX-RPC-Stil finden Sie unter "Ich mag Ihren Typ: Beschreiben und Aufrufen von Webdiensten basierend auf dem Diensttyp " ( JavaWorld, September 2002).)

Das Webdienstserver-Programmiermodell

Ein J2EE-basierter Webdienst kann einer von zwei möglichen Implementierungen folgen: Wenn der Dienst als reguläre Java-Klasse implementiert ist, muss er den Anforderungen des JAX-RPC-Servlet-Containers entsprechen. Wenn der Dienst für die Ausführung im EJB-Container definiert ist, muss er dem Programmiermodell folgen, das für zustandslose EJB-Session-Beans erforderlich ist. Unabhängig von der Implementierungsmethode bietet jeder Container der Webdienstimplementierung Lebenszyklusunterstützung, Parallelitätsverwaltung und eine Sicherheitsinfrastruktur.

Die Hauptverantwortung des J2EE-Servercontainers besteht darin, SOAP-Anforderungen im EJB-Fall zustandslosen Session-Beans und im Servlet-Container-Fall Methoden in JAX-RPC-Service-Endpunktklassen zuzuordnen und zu versenden. Während die JAX-RPC-Spezifikation ein Programmiermodell für die letztere Option definiert, beschreibt das JSR (JSR 109) der J2EE-Webdienste ein analoges Modell für zustandslose EJB-Session-Beans.