Advanced Java Services | Servlet Basics |
Ein Servlet kann nur in einem ServletContainer leben. Dieser steuert den ganzen Lebenszyklus eines Servlets. Die folgende Graphik erläutert die Hauptaufgaben des ServletContainers
Ähnlich wie ein Applet eine Unterklasse von java.awt.Applet ist (sein muß), so muß ein Servlet
das Inteface javax.servlet.Servlet implementieren. Meist stützt man sich jedoch auf die beiden
abstrakten Klassen GenericServlet bzw. HttpServlet, weil diese schon eine Teilimplementierung
liefern und leitet daher das eigene Servlet von GenericServlet oder von HttpServlet ab.
Aufgaben eines Servlet ist es, Anfragen eines Client zu beantworten. Dazu dient die Methode service,
die der Servletcontainer zu einem Servletobjekt ruft, falls eine Anfrage an das Servlet den
Server erreicht. Um diese Methode aufrufen zu können generiert der ServletContainer jeweils ein Objekt
vom Typ ServletRequest und ServletResponse. Dem ServletRequestObjekt wird dabei die Anfrage des Client
übergeben, sodaß die service-Methode darauf objektorientiert zugreifen kann. In der service()-Methode
wird dann das mitübergebene ServletResponseObjekt mit der Antwort "gefüllt", die dann nach
Beendigung der Methode dem Servletcontainer zur Verfügung steht.
Verwenden die Clientanfragen immer HTTP als Protokoll, so wird man das eigene Servlet als Ableitung
von HttpServlet realisieren, wogegen man durch Ableiten von GenericServlet auf jedes Protokoll reagieren
kann.
Die folgenden Graphiken erläutern das Design von Servlet, bzw. ServletRequest bzw. ServletResponse.
public class SkeletonServlet extends GenericServlet { // wird gerufen von super.init(ServletConfig config) public void init() throws ServletException { // to do : initialization } public void service(ServletRequest req, ServletResponse res) throws ServletException { // to do : reacting on the request } public void destroy() { // cleanup, release resources }
Wie bei einem Applet legt man Initialisierungen nicht in den Konstruktor, sondern in eine init() Methode. Bei der ersten Anforderung des Servlets instantiiert der ServletContainer ein Objekt von diesem Typ und ruft die init()-Methode. Der ServletContainer ruft jedoch nicht die oben erwähnte init()-Methode, sondern die init()-Methode, der er ein Objekt vom Typ ServletConfig übergibt. Da jedoch GenericServlet dieses Interface implementiert, braucht man keine eigene Instanz vom Typ ServletConfig. Man sieht jedoch aus nachstehendem Quelltext von GenericServlet, daß man über ServletConfig einen Zeiger auf einen ServletContext erhält. Sowohl ServletConfig als auch ServletContext werden vom ServletContainer angelegt und geliefert. Über ServletConfig kann man Parameter aus der web.xml auslesen, über den ServletContext kann man Information über andere Servlets erhalten und mit diesen Daten austauschen.
package javax.servlet; import java.io.IOException; import java.io.Serializable; import java.util.Enumeration; public abstract class GenericServlet implements Servlet, ServletConfig, Serializable { private transient ServletConfig config; public GenericServlet() { } public void init() throws ServletException { } public void init(ServletConfig servletconfig) throws ServletException { config = servletconfig; log("init"); init(); } public void destroy() { log("destroy"); } public ServletConfig getServletConfig() { return config; } // --------------- begin: von ServletConfig geforderte Methoden --------------- \\ public String getInitParameter(String s) { return getServletConfig().getInitParameter(s); } public Enumeration getInitParameterNames() { return getServletConfig().getInitParameterNames(); } public String getServletName() { return config.getServletName(); } public ServletContext getServletContext() { return getServletConfig().getServletContext(); } // --------------- end: von ServletConfig geforderte Methoden --------------- \\ public String getServletInfo() { return ""; } public void log(String s) { getServletContext().log(getServletName() + ": " + s); } public void log(String s, Throwable throwable) { getServletContext().log(getServletName() + ": " + s, throwable); } public abstract void service(ServletRequest servletrequest, ServletResponse servletresponse) throws ServletException, IOException; }
Wie man aus dem Quellcode erkennt, reicht es, die init()-Methode ohne Parameter zu überschreiben. Es ist zudem sicherer, denn beim Überschreiben der anderen init()-Methode besteht die Gefahr, daß man den super-Aufruf vergißt. In diesem Fall erhält die Membervariable config keinen Wert und man kann weder auf ServletConfig noch auf ServletContext zugreifen.
Wer implementiert diese abstrakte Klassen und Interfaces? Es gibt nur eine Möglichkeit und die heißt ServletContainer. Es folgen einige Realisierungen am Beispiel Tomcat 5.
(Abstrakte) Klasse oder Interface | Realisierung durch Tomcat 5 |
---|---|
ServletRequest | org.apache.coyote.tomcat5.CoyoteRequestFacade |
ServletResponse | org.apache.coyote.tomcat5.CoyoteResponseFacade |
BufferedReader | org.apache.coyote.tomcat5.CoyoteReader |
PrintWriter | org.apache.coyote.tomcat5.CoyoteWriter |
ServletInputStream | org.apache.coyote.tomcat5.CoyoteInputStream |
ServletOutputStream | org.apache.coyote.tomcat5.CoyoteOutputStream |
ServletContext | org.apache.catalina.core.ApplicationContextFacade |
ServletConfig | org.apache.catalina.core.StandardWrapperFacade |
HttpSession | org.apache.catalina.session.StandardSessionFacade |
Zum Auslesen der CGI-Umgebungsvariablen existieren eine ganze Reihe von Methoden, die entweder in ServletRequst oder in HttpServletRequst vereinbart sind. Die folgende Tabelle zeigt, mit welchen Methoden man in einem Servlet auf die CGI-Umgebungsvariablen zugreifen kann.
CGI-Umgebungsvariable | Methode | Interface |
AUTH_TYPE | String getAuthType() | HttpServletRequst |
CONTENT_LENGTH | int getContentLength() | ServletRequest |
CONTENT_TYPE | String getContentType() | ServletRequest |
HTTP_ACCEPT | String getHeader("Accept") | HttpServletRequest |
HTTP_REFERER | String getHeader("Referer") | HttpServletRequest |
HTTP_USER_AGENT | String getHeader("User-Agent") | HttpServletRequest |
PATH_INFO | String getPathInfo() | HttpServletRequest |
PATH_TRANSLATED | String getPathTranslated() | HttpServletRequst |
QUERY_STRING | String getQueryString() | HttpServletRequst |
REMOTE_ADDR | String getRemoteAddr() | ServletRequst |
REMOTE_HOST | String getRemoteHost() | ServletRequst |
REMOTE_USER | String getRemoteUser() | HttpServletRequest |
REQUEST_METHOD | String getMethod() | HttpServletRequest |
SERVER_NAME | String getServerName() | ServletRequst |
SERVER_PORT | int getServerPort() | ServletRequst |
SERVER_PROTOCOL | String getProtocol() | ServletRequst |
SERVER_SOFTWARE | String getServerInfo() | ServletContext |