Java Servlets sind serverseitige Java-Programme, die nach einem Request-Response-Schema arbeiten. Sie werden meistens als Erweiterung von Webservern im Zusammenhang mit HTTP in sogenannten Servlet-Containern eingesetzt. Innerhalb der Verarbeitung von Requests kann beliebiger Java-Code ausgeführt und so auch auf Ressourcen wie z.B. Datenbanken zurückgegriffen werden. Auf diese Weise dienen Servlets auch zum dynamischen Erzeugen von Webseiten.
Servlets haben bei der CGI-Programmierung gegenüber (Skript-)Sprachen wie Perl, Tcl/Tk und PHP vor allem einen Performance-Vorteil. Denn statt bei jedem Request teuer als externer Prozeß erzeugt und anschließend wieder zerstört zu werden, verbleiben Servlets bis zum Shutdown des Containers in der Instanz der JVM und können dort Requests dort nebenläufig verarbeiten. Zu den weiteren Vorteilen zählen die allgemeinen positiven Eigenschaften von Java: Objektorientiertheit, Plattformunabhängigkeit, Sicherheit, Stabilität. Die Java-Servlet-Technologie ist durch das Java Servlet API spezifiziert. Die aktuelle Version ist 2.3, aber die erweiterten Version 2.4 wird schon seit einiger Zeit entwickelt und hat bereits den Status "Proposed Final Draft", so daß damit gerechnet werden kann, daß sie die Version 2.3 in Kürze ablöst.
Abbildung 1 zeigt die grundlegende Schnittstellen und Klassen der Java Servlet API 2.3.
Abbildung 1: Die grundlegenden Schnittstellen und Klassen der Java Servlet API 2.3
In der Schnittstelle javax.servlet.Servlet
sind die Methoden eines Servlets definiert. Die wichtigsten drei sind:
init()
wird unmittelbar nach der Instanziierung des Servlets aufgerufen. Darin sollten Ressourcen erzeugt und initialisiert werden, die während der Requestverarbeitung benötigt werden.destroy()
wird beim Beenden des Servlets aufgerufen. Darin sollten alle Ressourcen, die in init()
erzeugt und initialisiert wurden, wieder freigegeben und beendet werden.service()
ist die zentrale Methode eines Servlets. In ihr wird der Request, der in Form einer Objektreferenz übergeben wird, verarbeitet. Die Ergebnisse der Verarbeitung werden in einem Response-Objekt gespeichert, dessen Referenz ebenfalls beim Aufruf übergeben wird und zu diesem Zeitpunkt noch leer ist. Der Rückgabewert von service()
ist daher void
.
Die Schnittstelle javax.servlet.ServletConfig
definiert die Methoden für den Zugriff auf eine Servletkonfiguration. Beide Schnittstellen sowie die Schnittstelle Serializable
aus dem Paket java.io
werden durch die abstrakte Klasse javax.servlet.GenericServlet
implementiert, die ein generisches und protokollunabhängiges Servlet darstellt. Sie wird beerbt von der abstrakten Klasse javax.servlet.HttpServlet
, in der die Methoden für die Verarbeitung von HTTP-Requests enthalten sind, und die somit eine geeignete Oberklasse ist, wenn eigene Servlets für das Web entwickelt werden sollen.
Listing 1 zeigt den Quellcode eines einfachen Servlets, das das als Request ein einfaches HTML-Dokument erzeugt.
import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class HelloWorldServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Arbeit an doPost() delegieren doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); // HTML-Ausgabe erzeugen out.println("<html>"); out.println("<head>"); out.println("<title>Hello World</title>"); out.println("</head>"); out.println("<body>"); out.println("<h1>Hello World</h1>"); out.println("</body>"); out.println("</html>"); } }
Listing 1: HelloWorldServlet.java
Um die gewünschte Arbeit zu erledigen, müssen in diesem einfachen Servlet werden nur doGet()
und doPost()
überschrieben werden. Weil es unerheblich sein soll, ob es sich um einen GET- oder einen POST-Request handelt, delegiert doGet()
die Arbeit an doPost()
. Genausogut könnte doPost()
die Arbeit an doGet()
delegieren.
Weil das Beispielservlet keine externen Ressourcen benötigt, die initialisiert und nach der Bearbeitung wieder freigegeben werden müßten, werden weder init() noch destroy(), überschrieben. Auch die Default-Implementierung von service() wird aus der Oberklasse HttpServlet übernommen.
Wie das Beispiel aus dem vorherigen Abschnitt zeigt, können mit Servlets ganze HTML-Dokumente erzeugt werden. In der Praxis ist es aber etwas umständlich, sämtliche Ausgaben von Servlets erzeugen zu lassen. Denn zum einen sind die vielen Aufrufe von println()
unelegant und zum anderen ist der Verantwortliche für die Gestaltung der Oberfläche vielleicht ein HTML-Experte, hat aber möglicherweise keine Java-Kenntnisse. Das größte Manko ist aber, daß jede noch so kleine Änderung erneutes Kompilieren und Deployen des Servlets erforderlich macht.
Abhilfe schaffen hier JavaServer Pages (JSP), die in der JavaServer Pages API spezifiziert sind. Die Quelle einer JSP ist eine einfache HTML-Datei, die außer Plaintext und den HTML-Tags innerhalb gekennzeichneter Bereiche Java-Code enthalten kann. Dieses Prinzip wird auch bei Skriptsprachen wie z.B. Perl oder PHP verwendet, mit dem Unterschied, daß dort nicht Java-, sondern Perl- bzw. PHP-Code notiert wird.
Anders als bei den Skriptsprachen werden JSPs aber nicht interpretiert, sondern mittles eines JSP-Compilers kompiliert und so in Servlets umgewandelt. Eine JSP kann also quasi als Bauanleitung für ein Servlet aufgefaßt werden. Die Umwandlung erfolgt in zwei Schritten: Im ersten Schritt der Java-Quellcode eines Servlets erstellt, der der JSP entspricht. Im zweiten Schritt wird dieser Quellcode kompiliert und deployed. Dieser Vorgang muß aber nicht nach jeder Änderung der JSP manuell vom Entwickler angestoßen werden, sondern passiert jedes Mal, wenn die JSP in einem Request angefordert wird.
Abbildung 2 zeigt den Ablauf, wie eine JSP in ein Servlet übersetzt und geladen wird.
Abbildung 2: Übersetzen und Laden einer JSP
Listing 2 zeigt eine JSP, die die gleiche Ausgabe erzeugt, wie das Servlet aus Listing 1.
<%! String msg = new String("Hello World"); %> <html> <head> <title>Hello World</title> </head> <body> <h1><% out.println(msg); %></h1> </body> </html>
Listing 2: helloworld.jsp
Um Java-Code von den restlichen Inhalten einer JSP abzugrenzen, werden die Bereiche, in denen Java-Code steht mit <%
und %>
gekennzeichnet. Je nachdem, ob dem öffnenden <%
unmittelbar ein @
, ein !
, ein =
oder kein weiteres Sonderzeichen folgt, handelt es sich um eine Direktive, eine Deklaration, einen Ausdruck oder ein Scriptlet. In der ersten Zeile helloworld.jsp steht eine Deklaration: es wird ein String-Objekt mit dem Namen msg und der Initialisierung "Hello World" deklariert. Einige Zeilen später wird der Wert von msg im Rahmen eines Scriptlets ausgegeben. Dabei wird println()
des implizit deklarierten Objektes out
aufgerufen. Weitere implizite Objekte sind request
, response
, pageContext
, session
, application
, config
, page
und exception
.
Alle Bereiche, die nicht Java-Code darstellen, sind für den JSP-Compiler String-Konstanten. In dem von ihm erzeugten Servlet werden sie mittels Aufrufen von out.write()
ausgegeben. Davon kann man sich überzeugen, indem man den Java-Quellcode betrachtet, den der JSP-Compiler für die jeweilige JSP erzeugt hat. Der Quellcode, den der JSP-Compiler Jasper aus der oben stehenden helloworld.jsp generiert, wird in Listing 7 im Abschnitt "Jasper" dargestellt.
Mit Java Servlets und anderen serverseitigen Technologien kann man mehr machen, als bloß dynamisch HTML-Dokumente zu erzeugen. Es lassen sich Anwendungen erstellen, deren Datenhaltung und Verarbeitungslogik auf dem Webserver stattfindet, während die Bedienung durch den Browser des Benutzers erfolgt. Solche Web-Anwendungen haben den Vorteil, daß sie praktisch von jedem Rechner mit Internetzugang und Browser bedient werden können.
Für Java-basierte Web-Anwendungen wurde der Begriff der Web-Application geprägt. Darunter wird eine Menge zusammengehöriger
verstanden.
Web-Applications können in sog. WAR-Files (WAR: Abkürzung für Web Application Archive). Dabei handelt es sich um JAR-Files, die eine besondere Struktur und bestimmte Dateien, u.a. den die Web-Application beschreibenden "Deployment Descriptor", beinhalten müssen. Durch den Einsatz von WAR-Files lassen sich ganze Web-Applications sehr einfach verteilen und installieren.
Jakarta Tomcat ist ein Container für Web-Applications und stellt in der aktuellen Version 4 die offizielle Referenz-Implementierung des Servlet 2.3 API und des JSP 1.2 API dar. Er wird im Rahmen des Apache Jakarta Projektes vollständig in Java entwickelt und ist somit für viele Betriebssysteme, unter anderem Linux und Windows, verfügbar.
Die Entwicklung von Tomcat begann 1999 mit der Zusammenführung von "JServ", der ersten frei erhältlichen Servlet-Anbindung für den Apache HTTP Server, und den Ansätzen anderer Hersteller unter der Bezeichnung "Tomcat 3". Der daraus entstandene Code implementierte zwar das Servlet 2.2 API und das JSP 1.1 API, war aber schwer wartbar und schlecht erweiterbar, weshalb die Tomcat-3-Konzeption in Version 3.3 noch einmal sauber implementiert wurde.
Für die Implementierung des Servlet 2.3 API und des JSP 1.2 API in Version 4 wurde eine völlig neue Tomcat-Architektur entworfen, deren Name "Catalina" in der Dokumentation und der Literatur manchmal synonym mit Tomcat 4 benutzt wird, und sich auch in Paket-, Klassen- und Variablennamen widerspiegelt. Catalina zeichnet sich durch leichte Erweiterbarkeit dank hoher Modularität und Verwendung vieler Entwurfsmuster aus. Der JSP-Container von Tomcat hat den Namen "Jasper". Er läuft gemäß des Servlet 2.3 API als Servlet. Er kann aber auch unabhängig von Catalina benutzt werden, z.B. um eine JSP von der Kommandozeile aus zu kompilieren.
Mit der Entwicklung von Version 5, die das Servlet 2.4 API und des JSP 2.0 API implementieren wird, wurde bereits begonnen. Bisher wurde aber noch kein Release veröffentlicht.
Die folgende Tabelle zeigt die verschiedenen Tomcat-Versionen und die der implementierten APIs.
Tomcat Version | Servlet API | JSP API |
---|---|---|
3.x | 2.2 | 1.1 |
4.x | 2.3 | 1.2 |
5.x | 2.4 | 2.0 |
Tabelle 1: Tomcat- und API-Versionen