Servlet Verständnissfrage

Hi,

wird von einem Servlet eigentlich nur eine Instanz/Objekt vom Tomcat erstellt od. wird bei jedem Aufruf eine neue/weitere Instanz erstellt?

Ich habe das Problem, das ich von einem Servlet aus, auf einem anderen Server Daten abfragen will. Da ich nicht jedes mal, wenn das Servlet aufgerufen wird den Server anfragen will, dachte ich kann ich die Daten mit einem Thread alle 10 Sekunden abfragen und diese dann vom Servlet abfragen. Wie sollte ich den Thread programmieren, damit auch dieser nicht bei jedem Servletaufruf neuerstellt wird? Ich brauche ja nur einen für alle Servletanfragen.

Ich hoffe ich hab mich einigermaßen verständlich ausgedrückt…

Danke schonmal, Gruß Bonkers

Hallo.

Hi,

wird von einem Servlet eigentlich nur eine Instanz/Objekt vom
Tomcat erstellt od. wird bei jedem Aufruf eine neue/weitere
Instanz erstellt?

Hier ppt-Präsentation zum Thema: http://ise.umit.at/teaching/swpg_folder/external/ref…
-> 1 Instanz, multiple Aufrufe

Ich habe das Problem, das ich von einem Servlet aus, auf einem
anderen Server Daten abfragen will. Da ich nicht jedes mal,
wenn das Servlet aufgerufen wird den Server anfragen will,
dachte ich kann ich die Daten mit einem Thread alle 10
Sekunden abfragen und diese dann vom Servlet abfragen. Wie
sollte ich den Thread programmieren, damit auch dieser nicht
bei jedem Servletaufruf neuerstellt wird? Ich brauche ja nur
einen für alle Servletanfragen.

…und hier noch zwei Resourcen: http://www.tomcat.objektpark.org/howto/index.html
http://www.moreservlets.com/

HTH
mfg M.L.

Nicht ganz richtig…
Hallo -

Hier ppt-Präsentation zum Thema:
http://ise.umit.at/teaching/swpg_folder/external/ref…
-> 1 Instanz, multiple Aufrufe

  1. Das kann/muß man im Deployment Descriptor (also web.xml) definieren.
  2. Eine Seite weiter im ppt sieht man das auch

Standardmäßig werden von Servlet-Engines sogar grundsätzlich mehrere Instanzen erzeugt, die gleichzeitig Requests abhandeln können (Servletpool). Da gibt es Werte für Anzahl der Instanzen beim Start, Maximale Anzahl der Instanzen (Es werden zur Laufzeit dynamisch weitere Instanziert, falls es mal nicht reicht), etc. etc.

Wenn man explizit nur eine Instanz haben will, muß man das meist auch extra sagen. Man handelt sich dabei aber einen extremen Flaschenhals ein - Denn wenn man dann mehrere gleichzeitige Requests auf das Servlet hat, warten eben alle, bis sie jeweils drankommen.

Meine Erfahrungen basieren allerdings nur auf der Resin-Servlet-Engine von Caucho, die da auch sehr auf laufenden Betrieb ausgelegt ist. Aber ich kann mir vorstellen, dass das bei Tomcat genauso ist.

mfG,

J.P.Jarolim

static variablen?
Hi -

Eine Möglichkeit wäre diese: Du richtest dir eine static Variable in der Servlet-Klasse ein, die die gewünschten Daten hält. Dh. Jede Instanz des Servlets sieht so auf den gleichen Datenpool.

Dazu noch ein Datum

static Date lastTimeRequested

und eine Methode die die Daten nur holt, wenn lastTimeRequested mindestens 10 Sekunden her ist und sonst abbricht. Die Methode schreibt dann das Ergebnis in das static Datenfeld. Also selber einen Cache einrichten.

Du mußt halt auch noch für Datensicherheit bei den Aufrufen sorgen - Wie’s halt so ist mit Multithreading. Eventuell mit einer static boolean lockVar oder so was. Oder die getter- und setter Methoden synchronized erklären.

Eine weitere Möglichkeit wäre, dass du die Daten in den APPLICATION-Scope deiner Web-Anwendung schreibst. Dort kann sie jede Komponente (servlet/jsp) jederzeit sehen und manipulieren. Da mußt du aber auch auf das Multithreading aufpassen.

mfG,

J.P.Jarolim

Hi -

Nochmal ich… Mit welcher Tomcat-Version arbeitest du denn? Soviel ich mich erinnern kann, gibt es in der neuesten Servlet-Spezifikation einen Timer-Service. Dh. Du kannst eine Klasse schreiben (Mit den richtigen Interfaces eingebunden), die die Serverabfrage macht und irgendwohin (zB. DB) speichert. In der web.xml kannst du dann spezifizieren, in welchen Zeitintervallen die Klasse dann aufgerufen werden soll.

Damit hast du eine lässige Zeitentkoppelung - Deine Servlets zeigen dann jeweils nur die Daten vom letzten Aufruf her und laufen daher flott.

Ich glaub, das geht ab Servlets 2.3. Der neueste Tomcat sollte das schon unterstützen.

mfG,

J.P.Jarolim

Nö leider - Ist eine proprietär Resin
Ich habe nachgeschaut - Ist leider eine proprietäre Erweiterung der Resin-Servlet Engine.

Aber gegen einen cron (unix etc.) bzw. at (windows) - Job spricht ja nix, der regelmäßig auf der Maschine läuft.

Man kann aber auch einen Thread über ein Servlet starten - Allerdings muß man dann ganz genau aufpassen, dass man den auch wieder sauber stoppt, wenn das startende Servlet aus dem Servletpool rausgenommen wird (Kann jederzeit passieren).

mfG,

J.P.Jarolim

Hi, danke für die tips. Bin gerade dabei zu versuchen den thread kontrolliert zu starten und zu stopen, jedoch habe ich noch nicht verstanden, wie ich den auch wirklich anhalten kann. Wenn er gerade sleep aufgerufen hat, bekomme ich immer eine InterruptException. Ich benutze den Tomcat in JBoss 4.0.2, das ist eine 5er Version.

Gruß Bonkers

Bin gerade dabei zu versuchen den
thread kontrolliert zu starten und zu stopen, jedoch habe ich
noch nicht verstanden, wie ich den auch wirklich anhalten
kann. Wenn er gerade sleep aufgerufen hat, bekomme ich immer
eine InterruptException.

Die Frage ist generell, wer den Thread startet. Du hast höchstwahrscheinlich nicht nur Servlet-Pools sondern auch Thread-Pools in der Tomcat Servlet-Engine. Dh. Ein und dasselbe Servlet kann von einem der gerade freien Threads abgehandelt werden. So Sachen wie Threadlocal-Variablen werden da recht schwierig.

Ich habs zwar noch nie probiert, aber ich schätze, dass nur der den Thread schließen kann, der ihn auch geöffnet hat. Damit ist ein Servlet als Starter eines eigenen Threads, der länger als der Request dauern soll, ziemlich ungeeignet, da das Servlet beim nächsten Aufruf höchstwahrscheinlich über einen anderen Thread ausgeführt wird.

Und es ist auch definitiv kein Teil der Servlet-Spec, wie das die einzelnen Servlet-Container machen (Man mag durchaus einen Servlet-Container schreiben, der nur einen zentralen Thread hat - Dürfte halt nicht sehr performant sein). Also kann dein Code, den du jetzt für die Tomcat schreibst, auf einer anderen Servlet-Engine große Probleme verursachen.

Schau dich lieber um, wie du das anders (ohne Thread oder nur mit dem Lifecycle-Modell der Servlets) lösen kannst: Du hast ja JBoss hinten: Stoss doch zB. einen Message Driven Bean an, die Daten zu holen und abzulegen - Dann bist du zeitlich perfekt entkoppelt.

mfG,

J.P.Jarolim

Ich benutze den Tomcat in JBoss
4.0.2, das ist eine 5er Version.

Gruß Bonkers

1 „Gefällt mir“

Hi,

stimmt mit dem JBoss könnte man das machen, nur leider wollte ich nicht den großen Aufwand in ein kleines Programm/Servlet stecken. Ich erstelle jetzt den Thread in meinem Servlet in der init() und zerstöre ihn in der destroy() des Servlets. Das sollte so weit dann sicher sein, außerdem ist der Thread statisch, wie Du es vorgeschlagen hattest. Damit dürfte maximal ein Thread pro Servletinstanz laufen, evtl. sogar nur einer (weil statisch)? Das hab ich noch nicht so recht begriffen. Habe gelesen, das man den Tomcat konfigurieren kann, ob er mehrer Instanzen eines Servlets erstellen soll und unter welchen Bedingungen er das macht usw.

Vielen Dank nochmal für Deine Hilfe.

Gruß Bonkers

static usw
Hi -

stimmt mit dem JBoss könnte man das machen, nur leider wollte
ich nicht den großen Aufwand in ein kleines Programm/Servlet
stecken.

Wo du recht hast, hast du recht :wink:

Ich erstelle jetzt den Thread in meinem Servlet in
der init() und zerstöre ihn in der destroy() des Servlets. Das
sollte so weit dann sicher sein,

Die Init- bzw. Destroy-Methoden werden (wenn ich dich richtig verstanden habe) nicht dann aufgerufen, wenn du das möchtest. Der Servlet-Container kann das machen, wann er will. Die Init-Methode wird normalerweise nur beim Server- bzw. Applikationsstart aufgerufen (Und wenn Aufgrund hoher Auslastung noch mehr Instanzen von dem Servlet benötigt werden). Dh. Wenn Tomcat beim hochfahren standardmäßig 20 Instanzen deines Servlets in den Speicher stellt, wird dein Thread 20 mal gestartet (Ausser du sagtst in der Web.xml dass du nur max. 1 Servlet starten möchtest = Bottleneck).

Du hast ebenfalls nicht unter Kontrolle, wann die destroy-Methode eines Servlets aufgerufen wird. Benötigt der Server Speicher für andere Sachen, kann es dir passieren dass deine Servlets nacheinander aus dem Speicher gekickt werden - Inclusive deinem Datenthread. Dh. du kannst dir nicht sicher sein, dass der Thread auch wirklich immer ausgeführt wird.

Was für dich interessant sein dürfte ist folgendes: Die Ausführung eines Servlets muß nicht wirklich mit der Ausgabe an den Browser abgeschlossen sein. Dh. Du kannst nach dem Senden des Outputs oder nach dem Senden eines Redirects ruhig noch Code schreiben und ausführen lassen.

Ich würde dir wirklich die allererste Variante empfehlen:

Dein(e) Servlet(s) haben einen static Timestamp (static erkläre ich unten nochmal), welcher bei jeder Datenabfrage auf die aktuelle Zeit geupdatet wird.

ZB. static Date lastDatenAbfrage;

Zusätzlich speicherst du die Abgefragten und geparsten Daten in ein static Datenfeld, damit alle Servlets drauf zugreifen können.

Nach der Ausgabe von deinem Servlet startest du den Zugriff auf den Server - Allerdings nur, wenn die letzte Datenabfrage mindestens 20 Sekunden alt ist.

ZB.

Date currentDate = new Date();
long mindestZeitabstandInMs = 20*1000; // 20 Sekunden
if (currentDate().getTime()-mindestZeitabstandInMs > lastDatenAbfrage.getTime()) {
// Super tolle Serverabfrage
// Ergebnis parsen
// Ergebnis in static Datenfeld schreiben
}

Jetzt hast du nur noch einen Sonderfall: Beim allerersten Aufruf des Servlets hast du keine Daten in deinem static Datenfeld. Dh. Entweder schreibst du dann „Bitte warten, Reload drücken“ oder du befüllst das Datenfeld in deiner Init-Methode mit Default-Daten.

…außerdem ist der Thread
statisch, wie Du es vorgeschlagen hattest. Damit dürfte
maximal ein Thread pro Servletinstanz laufen, evtl. sogar nur
einer (weil statisch)? Das hab ich noch nicht so recht
begriffen.

Uhuh - Bitte sei da Vorsichtig - Ich habe statische Variablen und nicht statische Threads gemeint. Statische Variablen sind eines der zentralen Konzepte von Java: Bitte schau dir das unter http://java.sun.com/docs/books/tutorial/java/javaOO/… nochmal an.

Nur kurz zu dem, was ich meine: Wenn du eine normale Variable in einer Klasse definierst, dann ist diese jeweils an die Instanz gebunden. Dh. Jede Instanz einer Klasse (Also in deinem Fall jedes von Tomcat instanzierte Servlet deiner Servletklasse) hat eine eigene Variable.

Wenn du die Variable als static deklarierst, ist sie an die Klasse selber gebunden. Dh. Jede Instanz / Jedes Servlet der Klasse hat einfach nur einen „Zeiger“ auf die eine globale Variable.

Kleines Beispiel:

public class BooNormal {
String value = „“;
}

a = new BooNormal();
b = new BooNormal();
a.value = „1“;
b.value = „2“;

a.value enthält jetzt „1“ und b.value enthält „2“, da die beiden Variablen jeweils an die Instanz gebunden und somit unabhängig sind.

Jetzt static:

public class BooStatic {
static String value = „“;
}

a = new BooStatic();
b = new BooStatic();
a.value = „1“;
b.value = „2“;

a.value zeigt auf den gleichen Speicherplatz wie b.value - Dh. a.value = b.value = „2“.

Auf diesem Weg kannst du zwischen verschiedenen Instanzen einer Klasse (Also den einzelnen von Tomcat instanzierten Instanzen deines Servlets) Daten direkt ausstauschen.

Habe gelesen, das man den Tomcat konfigurieren
kann, ob er mehrer Instanzen eines Servlets erstellen soll und
unter welchen Bedingungen er das macht usw.

Ja - Man sollte eigentlich immer selber konfigurieren, was man haben will. Standardmäßig Instanziert Tomcat mehrere Instanzen pro Servlet, damit er auch mehrere gleichzeitige Requests abhandeln kann. Schau dir mal den Bereich in der Beschreibung der web.xml an. In dieser Datei (Sie liegt normalerweise im Verzeichnis WEB-INF) sollten alle Servlets eingetragen und konfiguriert werden. Sonst nimmt die Servlet-Engine (Tomcat) grundsätzlich immer Defaultwerte.

Vielen Dank nochmal für Deine Hilfe.

np

Gruß Bonkers

mfG,

J.P.Jarolim

1 „Gefällt mir“

hi, vielen dank, ich denke ich werde das mit dem timestamp so umsetzen. das mit der statischen variable habe ich so gemacht, halt nur mit einer Threadvariablen. außerdem habe ich mir die option zum starten und stopen eingebaut… naja etwas semiprofessionell :smile:

gruß bonkers

p.s. etwas spät geantwortet weil ich auch noch das thema weiter oben auf dem schreibtisch habe