Angenommen, ich habe einen Webserver, der zahlreiche Servlets enthält. Für Informationen, die zwischen diesen Servlets übergeben werden, setze ich Sitzungs- und Instanzvariablen.
Wenn nun zwei oder mehr Benutzer eine Anfrage an diesen Server senden, was passiert dann mit den Sitzungsvariablen? Sind sie alle für alle Benutzer gleich oder werden sie für jeden Benutzer unterschiedlich sein? Wenn sie sich unterscheiden, wie konnte der Server zwischen verschiedenen Benutzern unterscheiden?
Eine ähnlichere Frage: Wenn n
Benutzer auf ein bestimmtes Servlet zugreifen, wird dieses Servlet nur beim ersten Zugriff des ersten Benutzers instanziiert oder wird es für alle Benutzer separat instanziiert? Mit anderen Worten, was passiert mit den Instanzvariablen?
Wenn der Servlet-Container (wie Apache Tomcat ) gestartet wird, werden alle seine Webanwendungen bereitgestellt und geladen. Wenn eine Webanwendung geladen wird, erstellt der Servlet-Container das ServletContext
einmal und speichert es im Speicher des Servers. Der web.xml
der Webanwendung und alle darin enthaltenen web-fragment.xml
-Dateien werden analysiert, und jeder gefundene <servlet>
, <filter>
und <listener>
(oder jede mit @WebServlet
, @WebFilter
und @WebListener
versehene Klasse) wird einmal instanziiert und im Server gespeichert. Für jeden instanziierten Filter wird seine Methode init()
mit einem neuen FilterConfig
aufgerufen.
Wenn ein Servlet
einen Wert für <servlet><load-on-startup>
oder @WebServlet(loadOnStartup)
hat, der größer als 0
ist, wird seine Methode init()
auch beim Start mit einem neuen ServletConfig
aufgerufen. Diese Servlets werden in der durch diesen Wert angegebenen Reihenfolge initialisiert (1
ist 1st, 2
ist 2nd usw.). Wenn für mehr als ein Servlet derselbe Wert angegeben ist, wird jedes dieser Servlets in der Reihenfolge geladen, in der sie im Klassenladeprogramm für web.xml
, web-fragment.xml
oder @WebServlet
aufgeführt sind. Wenn der Wert "load-on-startup" fehlt, wird die Methode init()
immer dann aufgerufen, wenn die HTTP-Anforderung dieses Servlet zum ersten Mal trifft.
Wenn der Servlet-Container mit allen oben beschriebenen Initialisierungsschritten fertig ist, wird ServletContextListener#contextInitialized()
aufgerufen.
Wenn der Servlet-Container heruntergefahren wird, werden alle Webanwendungen entladen, die Methode destroy()
aller initialisierten Servlets und Filter aufgerufen und alle Instanzen ServletContext
, Servlet
, Filter
und Listener
werden in den Papierkorb verschoben. Schließlich wird die ServletContextListener#contextDestroyed()
aufgerufen.
Der Servlet-Container ist an einen Webserver angeschlossen, der auf HTTP-Anforderungen über eine bestimmte Portnummer wartet (Port 8080 wird normalerweise während der Entwicklung und Port 80 in der Produktion verwendet). Wenn ein Client (z. B. Benutzer mit einem Webbrowser oder programmgesteuert mit URLConnection
) eine HTTP-Anforderung sendet, erstellt der Servlet-Container neue HttpServletRequest
und HttpServletResponse
Objekte und übergibt sie an alle definierten Filter
in der Kette und schließlich an die Servlet
-Instanz.
Im Fall von Filter wird die Methode doFilter()
aufgerufen. Wenn der Code des Servlet-Containers chain.doFilter(request, response)
aufruft, fahren die Anforderung und die Antwort mit dem nächsten Filter fort oder drücken auf das Servlet, wenn keine weiteren Filter vorhanden sind.
Im Fall von Servlets wird die Methode service()
aufgerufen. Standardmäßig bestimmt diese Methode, welche der doXxx()
-Methoden basierend auf request.getMethod()
aufgerufen wird. Wenn die ermittelte Methode im Servlet nicht vorhanden ist, wird in der Antwort ein HTTP 405-Fehler zurückgegeben.
Das Anforderungsobjekt bietet Zugriff auf alle Informationen zur HTTP-Anforderung, z. B. URL, Header, Abfragezeichenfolge und Text. Das Antwortobjekt bietet die Möglichkeit, die HTTP-Antwort nach Ihren Wünschen zu steuern und zu senden, indem Sie beispielsweise die Header und den Text festlegen können (normalerweise mit generiertem HTML-Inhalt aus einer JSP-Datei). Wenn die HTTP-Antwort festgeschrieben und abgeschlossen ist, werden sowohl das Anforderungs- als auch das Antwortobjekt wiederverwendet und zur Wiederverwendung bereitgestellt.
Wenn ein Client die Webapp zum ersten Mal besucht und/oder das HttpSession
zum ersten Mal über request.getSession()
abgerufen wird, erstellt der Servlet-Container ein neues HttpSession
-Objekt und generiert eine lange und eindeutige ID (die Sie verwenden können) get by session.getId()
) und speichert es im Speicher des Servers. Der Servlet-Container setzt außerdem ein Cookie
im Header Set-Cookie
der HTTP-Antwort mit JSESSIONID
als Namen und der eindeutigen Sitzungs-ID als Wert.
Gemäß der HTTP-Cookie-Spezifikation (ein Vertrag, den ein anständiger Webbrowser und Webserver einhalten muss) muss der Client (der Webbrowser) dieses Cookie bei nachfolgenden Anforderungen im Header Cookie
für zurücksenden solange der Cookie gültig ist (dh die eindeutige ID muss sich auf eine nicht abgelaufene Sitzung beziehen und die Domain und der Pfad sind korrekt). Mit dem integrierten HTTP-Verkehrsmonitor Ihres Browsers können Sie überprüfen, ob das Cookie gültig ist (drücken Sie F12 in Chrome/Firefox 23+/IE9 + und überprüfen Sie das Netz/Netzwerk tab). Der Servlet-Container überprüft den Cookie
-Header jeder eingehenden HTTP-Anforderung auf das Vorhandensein des Cookies mit dem Namen JSESSIONID
und verwendet seinen Wert (die Sitzungs-ID), um das zugeordnete HttpSession
aus dem Serverspeicher abzurufen.
HttpSession
bleibt so lange am Leben, bis es länger als den in <session-timeout>
angegebenen Zeitüberschreitungswert inaktiv war (d. H. In einer Anforderung nicht verwendet wurde), eine Einstellung in web.xml
. Der Timeout-Wert beträgt standardmäßig 30 Minuten. Wenn der Client die Webanwendung nicht länger als angegeben besucht, wird die Sitzung vom Servlet-Container in den Papierkorb verschoben. Jede nachfolgende Anfrage, auch mit dem angegebenen Cookie, hat keinen Zugriff mehr auf dieselbe Sitzung. Der Servlet-Container erstellt eine neue Sitzung.
Auf der Clientseite bleibt das Sitzungscookie so lange aktiv, wie die Browserinstanz ausgeführt wird. Wenn der Client die Browser-Instanz (alle Registerkarten/Fenster) schließt, wird die Sitzung auf der Client-Seite gelöscht. In einer neuen Browser-Instanz würde das mit der Sitzung verknüpfte Cookie nicht existieren, sodass es nicht mehr gesendet würde. Dadurch wird ein völlig neues HttpSession
erstellt, wobei ein völlig neues Sitzungscookie verwendet wird.
ServletContext
ist so lange gültig wie die Web-App. Es wird unter allen Anforderungen in allen Sitzungen geteilt.HttpSession
ist so lange gültig, wie der Client mit derselben Browserinstanz mit der Web-App interagiert und die Sitzung auf der Serverseite keine Zeitüberschreitung aufweist. Es wird zwischen allen Anforderungen in der gleichen Sitzung geteilt.HttpServletRequest
und HttpServletResponse
sind ab dem Zeitpunkt gültig, an dem das Servlet eine HTTP-Anforderung vom Client empfängt, bis die vollständige Antwort (die Webseite) eingegangen ist. Es wird nicht an anderer Stelle geteilt.Servlet
, Filter
und Listener
sind so lange gültig, wie die Web-App ausgeführt wird. Sie werden zwischen allen Anforderungen in allen Sitzungen geteilt.attribute
, das in ServletContext
, HttpServletRequest
und HttpSession
definiert ist, lebt so lange, wie das betreffende Objekt lebt. Das Objekt selbst stellt den "Gültigkeitsbereich" in Bean-Management-Frameworks wie JSF, CDI, Spring usw. dar. Diese Frameworks speichern ihre Gültigkeitsbereichsbeans als attribute
des am besten passenden Gültigkeitsbereichs.Das heißt, Ihr Hauptanliegen ist möglicherweise Thread-Sicherheit . Sie sollten jetzt wissen, dass Servlets und Filter von allen Anforderungen gemeinsam genutzt werden. Das ist das Schöne an Java, es ist multithreaded und verschiedene Threads (lesen Sie: HTTP-Anforderungen) können dieselbe Instanz verwenden. Andernfalls wäre es zu teuer, sie für jede einzelne Anforderung neu zu erstellen, init()
und destroy()
.
Sie sollten sich auch darüber im Klaren sein, dass Sie niemals Daten mit einem Anforderungs- oder Sitzungsbereich als Instanzvariable von zuweisen sollten ein Servlet oder Filter. Es wird mit allen anderen Anfragen in anderen Sitzungen geteilt. Das ist nicht threadsicher! Das folgende Beispiel veranschaulicht dies:
public class ExampleServlet extends HttpServlet {
private Object thisIsNOTThreadSafe;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Object thisIsThreadSafe;
thisIsNOTThreadSafe = request.getParameter("foo"); // BAD!! Shared among all requests!
thisIsThreadSafe = request.getParameter("foo"); // OK, this is thread safe.
}
}
Kurz: Der Webserver vergibt eine eindeutige Kennung an jeden Besucher bei seinem ersten Besuch. Der Besucher muss diesen Ausweis zurückbringen, damit er beim nächsten Mal wiedererkannt wird. Diese Kennung ermöglicht es dem Server auch, Objekte, deren Eigentümer eine Sitzung ist, ordnungsgemäß von denen einer anderen Sitzung zu trennen.
Wenn Laden beim Start falsch ist :
Wenn Laden beim Start wahr ist :
Sobald er sich im Servicemodus und im Groove befindet, bearbeitet das same Servlet die Anforderungen aller anderen Clients.
Warum ist es keine gute Idee, eine Instanz pro Client zu haben? Denken Sie darüber nach: Werden Sie für jede Bestellung einen Pizzabäcker einstellen? Wenn Sie das tun, haben Sie in kürzester Zeit kein Geschäft mehr.
Es ist jedoch mit einem geringen Risiko verbunden. Denken Sie daran: Dieser einzelne Mann hat alle Bestellinformationen in der Tasche. Wenn Sie also nicht vorsichtig sind Thread-Sicherheit für Servlets , gibt er möglicherweise einem bestimmten Kunden die falsche Bestellung.
Sitzung in Java-Servlets entspricht der Sitzung in anderen Sprachen wie PHP. Es ist für den Benutzer eindeutig. Der Server kann den Vorgang auf verschiedene Arten verfolgen, z. B. durch Cookies, das Umschreiben von URLs usw. In diesem Artikel von Java doc wird er im Zusammenhang mit Java-Servlets erläutert. Außerdem wird angegeben, wie die Sitzung verwaltet wird. Dies ist ein Implementierungsdetail, das den Konstrukteuren verbleibt des Servers. Die Spezifikation legt lediglich fest, dass sie für einen Benutzer über mehrere Verbindungen zum Server hinweg eindeutig sein muss. In diesem Artikel von Oracle finden Sie weitere Informationen zu beiden Fragen.
Edit Es gibt ein ausgezeichnetes Tutorial here , wie Sie mit Session innerhalb von Servlets arbeiten. Und here ist ein Kapitel von Sun über Java Servlets, was sie sind und wie man sie benutzt. Zwischen diesen beiden Artikeln sollten Sie in der Lage sein, alle Ihre Fragen zu beantworten.
Wenn der Servlet-Container (wie Apache Tomcat) gestartet wird, liest er aus der Datei web.xml (nur eine pro Anwendung), wenn etwas schief geht oder ein Fehler in der Containerseitenkonsole auftritt. Andernfalls wird das gesamte Web bereitgestellt und geladen Anwendungen mithilfe von web.xml (so genannt als Implementierungsdeskriptor).
Während der Instantiierungsphase des Servlets ist die Servlet-Instanz bereit, kann jedoch die Clientanforderung nicht bedienen, da sie mit zwei Informationen fehlt:
1: Kontextinformationen
2: Informationen zur Erstkonfiguration
Die Servlet-Engine erstellt das Interface-Objekt servletConfig, in dem die oben genannten fehlenden Informationen eingeschlossen sind. Die Servlet-Engine ruft init () des Servlets auf, indem sie die Objektreferenzen von servletConfig als Argument angibt. Sobald init () vollständig ausgeführt wurde, ist das Servlet bereit, die Clientanforderung zu bedienen.
A) nur einmal (für jede Clientanforderung wird ein neuer Thread erstellt) Nur eine Instanz des Servlets bedient eine beliebige Anzahl der Clientanfragen, dh, nachdem ein Clientanforderungsserver bedient wurde, stirbt er nicht. Sie wartet auf andere Client-Anforderungen, dh welche CGI-Einschränkung (für jede Client-Anforderung wird ein neuer Prozess erstellt wird) wird mit dem Servlet überwunden (die Servlet-Engine erstellt intern den Thread).
A) Immer wenn getSession () für das HttpServletRequest-Objekt aufgerufen wird
Schritt 1 : Anforderungsobjekt wird auf eingehende Sitzungs-ID ausgewertet.
Schritt 2 : Wenn die ID nicht verfügbar ist, wird ein brandneues HttpSession-Objekt erstellt und die entsprechende Sitzungs-ID wird generiert (dh von HashTable). Die Sitzungs-ID wird im httpservlet-Antwortobjekt gespeichert und die Referenz des HttpSession-Objekts wird an das Servlet zurückgegeben ( doGet/doPost).
Schritt 3 : Wenn die ID zur Verfügung steht, wird ein brandneues Sitzungsobjekt nicht erstellt. Die Sitzungs-ID wird aus der Abfrage des Anforderungsobjekts abgerufen. Die Sitzung wird in der Sammlung von Sitzungen unter Verwendung der Sitzungs-ID als Schlüssel durchgeführt.
Nach erfolgreicher Suche wird die Sitzungs-ID in HttpServletResponse gespeichert und die vorhandenen Sitzungsobjektverweise an doGet () oder doPost () von UserDefineservlet zurückgegeben.
1) Wenn die Kontrolle vom Servlet-Code an den Client übergeht, vergessen Sie nicht, dass das Session-Objekt vom Servlet-Container, dh der Servlet-Engine, gehalten wird
2) Multithreading wird Servlet-Entwicklern zum Implementieren überlassen, dh, die mehrfachen Anforderungen des Clients müssen sich nicht mit Multithread-Code beschäftigen
Ein Servlet wird erstellt, wenn die Anwendung gestartet wird (sie wird im Servlet-Container bereitgestellt) oder beim ersten Zugriff darauf (abhängig von der Einstellung für das Laden beim Start) Wenn das Servlet instanziiert ist, wird die Methode init () der Servlet heißt Dann verarbeitet das Servlet (seine einzige Instanz) alle Anforderungen (seine service () - Methode wird von mehreren Threads aufgerufen). Aus diesem Grund ist es nicht ratsam, eine Synchronisierung zu verwenden, und Sie sollten Instanzvariablen des Servlets vermeiden. Wenn die Anwendung nicht implementiert ist (der Servlet-Container wird angehalten), wird die destroy () -Methode aufgerufen.
Sitzungen - was Chris Thompson gesagt hat.
Instantiation - Ein Servlet wird instanziiert, wenn der Container die erste dem Servlet zugeordnete Anforderung empfängt (es sei denn, das Servlet ist so konfiguriert, dass es beim Start mit dem Element <load-on-startup>
in web.xml
geladen wird). Dieselbe Instanz wird für nachfolgende Anforderungen verwendet.
Die Servlet-Spezifikation JSR-315 definiert das Verhalten des Web-Containers in den Dienstmethoden (und den Methoden doGet, doPost, doPut usw.) eindeutig (2.3.3.1 Multithreading-Probleme, Seite 9):
Ein Servlet-Container kann gleichzeitige Anforderungen über den Dienst senden Methode des Servlets. Um die Anfragen zu bearbeiten, muss der Servlet Developer. müssen ausreichende Vorkehrungen für die gleichzeitige Verarbeitung mit mehreren Threads in der Dienstmethode.
Obwohl dies nicht empfohlen wird, kann der Entwickler mit Implementieren Sie die SingleThreadModel-Schnittstelle, die den Container benötigt um zu gewährleisten, dass sich in der .__ jeweils nur ein Anforderungsthread befindet. Servicemethode. Ein Servlet-Container kann diese Anforderung durch .__ erfüllen. Serialisierung von Anforderungen auf einem Servlet oder durch Aufrechterhalten eines Servlet-Pools Instanzen. Wenn das Servlet Teil einer Webanwendung ist, die Als vertreibbar gekennzeichnet, kann der Container einen Pool von Servlets enthalten Instanzen in jeder JVM, auf die die Anwendung verteilt ist.
Bei Servlets, die die SingleThreadModel-Schnittstelle nicht implementieren, wenn die Servicemethode (oder Methoden wie doGet oder doPost, die an die Servicemethode der abstrakten HttpServlet-Klasse gesendet werden.) wurde mit dem synchronisierten Schlüsselwort, dem Servlet-Container, definiert Die Instanzpoolmethode kann nicht verwendet werden, aber Anforderungen müssen serialisiert werden durch. Es wird dringend empfohlen, dass Entwickler nicht .__ synchronisieren. die Dienstmethode (oder die an sie gesendeten Methoden) in diesen Umstände wegen nachteiliger Auswirkungen auf die Leistung
Wie aus den obigen Erläuterungen hervorgeht, wird durch die Implementierung der SingleThreadModelEin Servlet kann durch den Servlet-Container Thread-Sicherheit gewährleistet werden. Die Containerimplementierung kann dies auf zwei Arten tun:
1) Serialisierung von Anforderungen (Warteschlangen) an eine einzelne Instanz - dies ist vergleichbar mit einem Servlet, das nicht SingleThreadModel BUT implementiert, das die service/doXXX-Methoden synchronisiert. ODER
2) Erstellen eines Pools von Instanzen - Dies ist eine bessere Option und ein Kompromiss zwischen dem Start/Initialisierungsaufwand/-zeit des Servlets und den restriktiven Parametern (Speicher/CPU-Zeit) der Umgebung, in der das Servlet gehostet wird.