Im vorherigen Artikel habe ich eine einfache Java -Webserver -Implementierung geschrieben, mit der nur einige statische Ressourcenanforderungen abgeschlossen werden können. Der in diesem Artikel implementierte Servlet -Container wurde basierend auf dem vorherigen Server leicht geändert, wobei die Verarbeitung von Servlet -Anfragen hinzugefügt wurde.
Programmausführungsschritte
1. Erstellen Sie ein ServerSocket -Objekt;
2. Rufen Sie die Akzeptanzmethode des ServerSocket -Objekts auf und warten Sie auf die Verbindung. Wenn die Verbindung erfolgreich ist, wird ein Socket -Objekt zurückgegeben, sonst wird es blockiert und gewartet.
3.. Rufen Sie den InputStream- und OutputStream -Byte -Streams aus dem Socket -Objekt ab, und diese beiden Streams entsprechen der Anforderungsanforderung bzw. Antwortantwort.
4. Verarbeiten Sie die Anforderung: Lesen Sie die InputStream -Byte -Stream -Informationen, konvertieren Sie sie in ein Zeichenfolgenformular und analysieren Sie sie. Die Analyse hier ist relativ einfach und erhält nur die Informationen zur URI -Informationen (einheitliche Ressourcenkennung).
5. Verarbeiten Sie die Antwort (in zwei Typen, Antwort der statischen Ressourcenanforderung oder der Antwort der Servlet -Anforderung): Wenn es sich um eine statische Ressourcenanforderung handelt, basierend auf den analysierten URI -Informationen, finden Sie die angeforderte Ressourcenressourcendatei aus dem Web_Root -Verzeichnis, lesen Sie die Ressourcendatei und schreiben Sie sie in den OutputStream -Byte -Stream. Wenn es sich um eine Servlet -Anforderung handelt, generieren Sie zunächst einen URLClassloader -Klassenlader, laden Sie die angeforderte Servlet -Klasse, erstellen Sie das Servlet -Objekt und führen Sie die Dienstmethode aus (schreiben Sie die Antwortdaten in OutputStream).
6. Schließen Sie das Sockelobjekt;
7. Gehen Sie zu Schritt 2 und warten Sie weiter auf die Verbindungsanfrage.
Code -Implementierung:
Abhängigkeiten hinzufügen:
<!-https://mvnrepository.com/artifact/javax.servlet/servlet-api-> <depungcy> <Groupid> javax.servlet </gruppeId> <artifactid> servlet-api </artifactid> <version> 2.3 </Version> </abhängig>
Servercode:
Paket ex02.pyrmont.First; importieren java.net.socket; import java.net.serversocket; import java.net.inetaddress; import Java.io.inputStream; import Java.io.outputStream; Import. ex02.pyrmont.staticResourceProcessor; öffentliche Klasse httpserver1 {// Service -Befehl private statische endgültige String -String -Shutdown_Command = "/stilldown"; public static void main (String [] args) {httpserver1 server = new httpServer1 (); // Warten auf den Verbindungsanforderungserver. } public void Await () {ServerSocket ServerSocket = null; int port = 8080; try {// Server -Socket -Objekt ServersSocket = new ServerSocket (Port, 1, inetaddress.getByName ("127.0.1")); } catch (ioException e) {e.printstacktrace (); System.exit (1); } // Schleife, um auf die Anforderung zu warten, while (true) {Socket Socket = null; InputStream input = null; OutputStream output = null; Versuchen Sie {// Warten Sie auf die Verbindung, nachdem die Verbindung erfolgreich ist, geben Sie einen Socket -Objekt -Socket = ServerSocket.accept () zurück; input = socket.getInputStream (); output = socket.getOutputStream (); // Erstellen Sie ein Anforderungsobjekt und analysieren Sie Request Request = New Request (Eingabe); Request.Parse (); // Überprüfen Sie, ob es sich um einen Stillgangsdienstbefehl handelt, wenn (request.geturi (). Equals (stilldown_command)) {break; } // Reaktionsobjekte Antwort erstellen Antwort = Neue Antwort (Ausgabe); Antwort.SetRequest (Anfrage); if (request.geturi (). startsWith ("/servlet/")) {// Anfrage URI startet mit/servlet/, wobei der Servlet -Anfrage ServletProcessor1 processor = new ServletProcessor1 (); processor.Process (Anfrage, Antwort); } else {// static ressourceresourceProcessor processor = new staticResourceProcessor (); processor.Process (Anfrage, Antwort); } // Socket Socket schließen.CLOSE (); } catch (Ausnahme e) {e.printstacktrace (); System.exit (1); }}}}Ständige Klasse:
Paket ex02.pyrmont; import java.io.file; public class Constants {public static final String web_root = system.getProperty ("user.dir") + Datei.Sesparator + "Webroot"; public static final String web_servlet_root = system.getProperty ("user.dir") + file.separator + "Ziel" + Datei.separator + "Klassen"; }Anfrage:
Paket ex02.pyrmont; import Java.io.inputStream; Import Java.io.ioxception; import Java.io.BufferedReader; Import Java.io.unsupportedenCodingException; import Java.util.Enumeration; Import Java.util.locale; javax.servlet.servletInputStream; Import Javax.Servlet.ServletRequest; öffentliche Klasse -Anfrage implementiert ServletRequest {private InputStream -Eingabe; private String uri; public request (InputStream Input) {this.input = input; } public String geturi () {return Uri; } /** * * Die Form des RequestString lautet wie folgt: * Get /index.html http /1.1 * Host: localhost: 8080 * Verbindung: Keep-Alive * cache-control: max-AGE = 0 * ... * Der Zweck dieser Funktion ist, /index.html String zu erhalten. index1 = requestString.indexof (''); if (index1! = -1) {index2 = requestString.indexof ('', index1 + 1); if (index2> index1) return requestString.substring (Index1 + 1, Index2); } return null; } // Lesen Sie eine Reihe von Zeichen aus der Socket StringBuffer Request = new StringBuffer (2048); int i; byte [] buffer = neues byte [2048]; try {i = input.read (puffer); } catch (ioException e) {e.printstacktrace (); i = -1; } für (int j = 0; j <i; j ++) {request.Append ((char) puffer [j]); } System.out.print (request.toString ()); Uri = Parseuri (Request.ToString ()); } / * Implementierung des ServletRequest * / public Object getAtTribute (String -Attribut) {return null; } public Enumeration <?> getAtTributenames () {return null; } public String getRealPath (String -Pfad) {return null; } public requestDispatcher getRequestDispatcher (String -Pfad) {return null; } public boolean issecure () {return false; } public String getCharacterCoding () {return null; } public int getContentLength () {return 0; } public String getContentType () {return null; } public servletInputStream getInputStream () löscht ioException {return null; } public Locale getlocale () {return null; } public Enumeration <?> getLocales () {return null; } public String getParameter (String -Name) {return null; } public map <?,?> getParametermap () {return null; } public Enumeration <?> getParameternames () {return null; } public String [] getParameterervalues (String -Parameter) {return null; } public String getProtocol () {return null; } public bufferedReader getReader () löscht ioException {return null; } public String getremoteaddr () {return null; } public String getremotehost () {return null; } public String getScheme () {return null; } public String getServerName () {return null; } public int getServerport () {return 0; } public void removeAttribute (String -Attribut) {} public void setAttribute (String -Schlüssel, Objektwert) {} public void setCharactercoding (String -Codierung) löst nicht unterstütztedEcodingException {}} ausAntwort:
Paket ex02.pyrmont; import java.io.outputstream; import Java.io.ioxception; import Java.io.fileInputStream; Import Java.io.filenotfoundException; Import Java.io.file; javax.servlet.servletoutputStream; öffentliche Klasse implementiert servletResponse {private statische endgültige int buffer_size = 1024; Anfrage anfordern; Ausgangsausgang; Printwriter -Schriftsteller; public response (outputStream output) {this.output = output; } public void setRequest (Anfrageanforderung) {this.Request = request; } // Die Webdatei in den Ausgabestream -Byte -Stream öffentliche void sendStaticResource () löscht ioException {byte [] bytes = new byte [buffer_size]; FileInputStream fis = null; try { / * request.geturi wurde durch request.getRequesturi * / file Datei = neue Datei (Constants.web_root, Request.geturi ()) ersetzt; fis = new FileInputStream (Datei); / * * Http response = status-line ((allgemeiner header | response-header | * entity header) crlf) crlf [message-body] status-line = * http-version sp status-code sp Beury-Phrase crlf */ int ch = fis.read (bytes, 0, buffer_size); while (ch! = -1) {output.write (bytes, 0, ch); ch = fis.read (bytes, 0, buffer_size); }} catch (FilenotFoundException e) {String errorMessage = "http/1.1 404 Datei nicht gefunden/r/n" + "Inhaltstyp: text/html/r/n" + "Inhaltslänge: 23/r/n" + "/r/n" + "<h1> fand </h1>"; output.write (errormessage.getBytes ()); } endlich {if (fis! = null) fis.close (); }} / ** Implementierung von servletResponse* / public void flushbuffer () löscht ioException {} public int getBufferSize () {return 0; } public String getCharacterCoding () {return null; } public Locale getlocale () {return null; } public servletOutputStream getoutputStream () löscht ioException {return null; } public printwriter getWriter () löscht ioException {// autoflush is true, println () wird flush, // print () nicht. writer = neuer printwriter (output, true); Rückfahrer; } public boolean isCommission () {return false; } public void reset() { } public void resetBuffer() { } public void setBufferSize(int size) { } public void setContentLength(int length) { } public void setContentType(String type) { } public void setLocale(Locale locale) { }}Statische Ressourcenanforderungsverarbeitung:
Paket ex02.pyrmont; import Java.io.ioException; öffentliche Klasse staticResourceProcessor {public void Process (Anfrage, Antwort, Antwort) {try {response.sendstaticResource (); } catch (ioException e) {e.printstacktrace (); }}}Servlet -Anforderungsverarbeitung:
Paket ex02.pyrmont.First; importieren java.net.url; import java.net.urlclassloader; import Java.net.urlstreamHandler; import Java.io.ioException; importieren javax.servlet.Servlet.Servlet.Servlet. Ex02.Pyrmont.Constants; Import EX02.Pyrmont.Request; Import EX02.Pyrmont.Response; public class servletProcessor1 {public void Process (Anfrage, Antwort, Antwort) {String uri = request.geturi (); String servletName = uri.substring (uri.lastindexof ("/") + 1); // Classloader, verwendet, um den Klassen -URLClassloader aus einer angegebenen JAR -Datei oder Verzeichnisloader = NULL zu laden; Versuchen Sie {urlstreamHandler streamHandler = null; // Class Loader Loader = new urlClassloader (neue URL [] {neue URL (NULL, "Datei:" + Constants.Web_Servlet_Root, StreamHandler)}); } catch (ioException e) {System.out.println (e.toString ()); } Class <?> Myclass = null; Versuchen Sie {// laden Sie die entsprechende Servlet -Klasse myclass = loader.loadClass (ServletName); } catch (classNotFoundException e) {System.out.println (e.toString ()); } Servlet servlet = null; Versuchen Sie {// produzieren servlet instance servlet = (servlet) myclass.newinstance (); // Die Dienstmethode der Ervlet Servlet.Service ((ServletRequest) -Anforderung, (ServletResponse) Antwort) ausführen; } catch (Ausnahme e) {System.out.println (e.toString ()); } catch (throwable e) {System.out.println (e.ToString ()); }}}Servlet -Klasse:
Javax.servlet importieren. } public void Service (ServletRequest Request, ServletResponse -Antwort) löst ServletException aus, ioException {System.out.println ("From Service"); Printwriter out = response.getWriter (); out.println ("Hallo. Rosen sind rot."); out.print ("Veilchen sind blau."); } public void destroy () {system.out.println ("zerstören"); } public String getServletInfo () {return null; } public servletConfig getServletConfig () {return null; }} Ergebnisse Test:
Statische Ressourcenanfrage:
Servlet -Anfrage (Da nur die erste Zeichenfolge in den Browser gespült wird, können Sie nicht sehen, dass die zweiten String -Veilchen blau sind. Wir werden den Container später verfeinern):
verbessern
Der zuvor implementierte Servlet -Container hat ein ernstes Problem. Im Servlet kann der Benutzer ServletRequest und ServletResponse in Anforderungs- und Antworttypen direkt verwandeln und seine internen öffentlichen Methoden direkt aufrufen. Dies ist ein schlechtes Design. Die Verbesserungsmethode besteht darin, Erscheinungsklassen zur Anfrage und Reaktion hinzuzufügen, damit Benutzer nur auf die in der Erscheinungsklasse definierten öffentlichen Methoden zugreifen können.
Erscheinungsklasse anfordern
Paket ex02.pyrmont.second; import java.io.ioxception; import java.io.buffenedReader; import Java.io.unsupportedenCodingException; Import Java.util.enumeration; Import Java.util.locale; javax.servlet.servletInputStream; import javax.servlet.servletRequest; importe ex02.pyrmont.request; öffentliche Klasse RequestFacade implementiert servletRequest {private servletRequest request = null; public requestFacade (Anfrageanforderung) {this.Request = request; } / * Implementierung des ServletRequest * / public Object getAtTribute (String -Attribut) {return request.getAttribute (Attribut); } public Enumeration <?> getAtTributenames () {return request.getAttributenames (); } @SuppressWarnings ("Abschaltung") public String getRealPath (String -Pfad) {return request.getRealPath (Pfad); } public requestDispatcher getRequestDispatcher (String -Pfad) {return request.getRequestDispatcher (Pfad); } public boolean issecure () {return request.issecure (); } public String getCharacterCoding () {return request.getaracacterencoding (); } public int getContentLength () {return request.getContentLength (); } public String getContentType () {return request.getContentType (); } public servletInputStream getInputStream () löscht ioException {return request.getInputStream (); } public Locale getlocale () {return request.getLocale (); } public Enumeration <?> getLocales () {return request.getLocales (); } public String getParameter (String -Name) {return request.getParameter (Name); } public map <?,?> getParametermap () {return request.getParametermap (); } public Enumeration <?> getParameternames () {return request.getParameternames (); } public String [] getParameterValues (String -Parameter) {return request.getParameterValues (Parameter); } public String getProtocol () {return request.getProtocol (); } public bufferedReader getReader () löscht ioException {return request.getReader (); } public String getremoteaddr () {return request.getRemoteaddr (); } public String getremotehost () {return request.getRemotehost (); } public String getScheme () {return request.getScheme (); } public String getSerVername () {return request.getSerVername (); } public int getServerport () {return request.getServerport (); } public void removeTtribute (String -Attribut) {request.removeAttribute (Attribut); } public void setAttribute (String -Schlüssel, Objektwert) {Request.SetAttribute (Schlüssel, Wert); } public void setCharactercoding (String coding) löst nicht unterstützteEncodingException {request.setcharactercoding (codieren) aus; }} Reaktionsauftrittsklasse
Paket ex02.pyrmont.second; import Java.io.ioException; import Java.io.printwriter; import Java.util.locale; import Javax.servlet.ServletResponse; Import Javax.Servlet.ServletOutputStream; privat -servletrlet.ResponS -Antwort. public responseFacade (Antwortantwort) {this.Response = Antwort; } public void flushbuffer () löst ioException {response.flushBuffer () aus; } public int getBufferSize () {return response.getBufferSize (); } public String getCharacterCoding () {return response.getCharacacterencoding (); } public Locale getlocale () {return response.getLocale (); } public servletOutputStream getoutputStream () löscht ioException {return response.getOutputStream (); } public printwriter getWriter () löscht ioException {return response.getWriter (); } public boolean isCommidT () {return response.iscommitt (); } public void reset () {response.reset (); } public void resetBuffer () {response.resetBuffer (); } public void setBufferSize (int size) {response.setBufferSize (Größe); } public void ResetbufferSize (Größe); } public void ResetbufferSize (int Größe); } public void setBufferSize (Größe); } public void setContentLength (int länge) {response.setContentLength (Länge); } public void setContentType (String -Typ) {response.setContentType (Typ); } public void setLocale (Gebietsschema) {response.setlocale (Gebietsschema); }}Bearbeitungsbedarfsanforderungsklasse:
Paket ex02.pyrmont.second; importieren java.net.url; import java.net.urlclassloader; import Java.net.urlstreamHandler; import Java.io.ioException; importieren javax.servlet.Servlet. Ex02.Pyrmont.Constants; Import EX02.Pyrmont.Request; Import EX02.Pyrmont.Response; public class servletProcessor2 {public void Process (Anfrage, Antwort, Antwort) {String uri = request.geturi (); String servletName = uri.substring (uri.lastindexof ("/") + 1); // Klassenloader, verwendet, um den Klassen -URLClassloader aus einer angegebenen JAR -Datei oder Verzeichnis Loader = NULL zu laden; Versuchen Sie {urlstreamHandler streamHandler = null; // Class Loader Loader = new urlClassloader (neue URL [] {neue URL (NULL, "Datei:" + Constants.Web_Servlet_Root, StreamHandler)}); } catch (ioException e) {System.out.println (e.toString ()); } Class <?> Myclass = null; Versuchen Sie {// laden Sie die entsprechende Servlet -Klasse myclass = loader.loadClass (ServletName); } catch (classNotFoundException e) {System.out.println (e.toString ()); } Servlet servlet = null; // Erscheinungsklassen zum Anfragen und Antwort hinzufügen, und Sicherheitsüberlegungen werden verhindern, dass Benutzer ServletRequest und ServletResponse in Anforderungs- und Antworttypen in Servlets direkt verwandeln, und rufen Sie ihre internen öffentlichen Methoden direkt an, da es in RequestFacade und Response Facade keine Analyse, SendStaticResource und andere Methoden gibt. RequestFacade requestFacade = new RequestFacade (Anfrage); ResponseFacade responseFacade = new responseFacade (Antwort); versuche {Servlet = (Servlet) myclass.newinstance (); Servlet.Service ((ServletRequest) RequestFacade, (ServletResponse) ResponseFacade); } catch (Ausnahme e) {System.out.println (e.toString ()); } catch (throwable e) {System.out.println (e.ToString ()); }}} Die anderen Codes entsprechen im Grunde genommen den gleichen wie der zuvor implementierte Servlet -Container.
Das Verifizierungsprogramm fordert statische Ressourcen bzw. Servlets an und stellt fest, dass die Ergebnisse mit dem zuvor implementierten Container übereinstimmen.
Referenz: "Eingehende Analyse von Tomcat"
@Author ein windartiger Coder
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.