2010-12-16 13 views
13

Ich habe eine Frage zu den Garantien, falls vorhanden, in dem folgenden Szenario (beachten Sie, dass die Frage nicht "Wie geht das auf andere Weise?", Die Frage bezieht sich wirklich auf die Reihenfolge des Ladens von Klassen im folgenden Fall (um besser zu verstehen, wie Klassenladen funktioniert).Reihenfolge des Ladens einer Klasse aus einer WAR-Datei

Hier ist das hypothetische Szenario ... Es gibt eine .war Datei, die die folgende (teilweise) Verzeichnisstruktur hat:

WEB-INF/classes/com/acme/Bunny.class 
. 
. 
. 
WEB-INF/lib/acme.jar 

Beide Bunny.class Dateien importieren andere Klassen von acme.jar

Bunny.class in WEB-INF/classes Referenzierung/... ist die einzige Klasse, die denselben Namen/Pfad hat, dass eine Klasse von acme.jar.

Die .jar Dateiacme.jar enthält auch com.acme.Bunny (und es verwendet, um eine keine Sonderklasse loader Tricks).

Ich verstehe, dass die Java-Spezifikation garantiert, dass eine Klasse nicht geladen wird, bis sie vom Programm tatsächlich verwendet (oder "manuell klasse-geladen") wird, weshalb, wenn Sie Tausende von .jar stopfen, Sagen wir, in einem .war beginnen die Klassenladeprogramme nicht mit dem Klassifizieren von Zehntausenden von Klassen.

(edit)

Aber was ist mit der Reihenfolge, in der die zwei Klassen in den obigen Beispielen geladen werden?

sollte formuliert wurden:

Aber wie wird entschieden, welche der zwei Klassen oben geladen wird?

oder so ähnlich :)

Es gibt eine Garantie dafür übernommen: com.acme.Bunny wird von com.acme ... vor jeder anderen Klasse verwendet werden.

Grundsätzlich auf Wikipedia, wird die folgende geschrieben:

Die komplexeste JAR Hölle Probleme unter Umständen entstehen die Vorteil der vollen Komplexität der das Classloading System nehmen. Ein Java Programm ist nicht erforderlich, um nur einen einzelnen "flachen" Classloader zu verwenden, sondern kann aus mehreren (oder in fact, einer unbestimmten Anzahl von) verschachtelten, kooperierenden Classloadern bestehen.Klassen geladen von verschiedenen Klassenlatern können interagieren in komplexer Weise nicht vollständig von einem Entwickler, der zu unerklärlichen Fehlern oder Bugs.

Also ich frage mich: kann ich sicher sein, dass /classes/com/acme/Bunny.class wird vor dem aus .jar innerhalb des WEB-INF/lib/ classloaded werden dir oder nicht?

+0

Beachten Sie, dass ich nicht versuche, .jar Hölle zu lösen. Wenn ich es wäre, würde ich OSGi verwenden. Das Ziel ist es, ein bisschen besser zu verstehen, wie die Dinge unter der Haube funktionieren. – SyntaxT3rr0r

+0

bezogen: http://Stackoverflow.com/questions/1669305/how-does-jvm-deal-mit-duplicate-jars-of-different-versions – meriton

Antwort

10

This question kann eine Hilfe sein.

Die Servlet-Spezifikation ist dazu vage. Man würde erwarten, dass "WEB-INF/classes" vor "WEB-INF/lib" durchsucht wird, aber es scheint, dass es an dem Servlet-Container liegt zu entscheiden. Sie können nur sicher sein, dass der Container konsistent nacheinander geladen wird. Sie sollten also nie beide Klassen im selben Container sehen. Der Suchpfad kann konfigurierbar sein, abhängig von Ihrem Container.

Entschuldigung, ich kann nicht spezifischer sein: Willkommen in der Welt der mehreren Servlet-Container. Lass mich nicht mit Websphere-Spielen anfangen.

+10

Die [Servlet 2.4 spec] (http://download.oracle.com/otn-pub/ jcp/servlet-2.4-de-spec-oth-JSpec/servlet-2_4-de-spec.pdf) sagt: "Der Klassenladeprogramm für Webanwendungen muss zuerst Klassen aus dem Verzeichnis WEB-INF/classes und dann aus Bibliotheks-JARs laden im Verzeichnis WEB-INF/lib. " Ähnlich für Servlet 3.0 auch. –

+0

Huh. So ist es. Ich muss mir eine frühere Spezifikation angeschaut haben (oder war total verwirrt). Vielen Dank für die Klärung, @BradCupit. –

+4

@Cameron Skinner Könnten Sie bitte die Antwort auf die richtige bearbeiten. – alphablue

0

Sie scheinen zwei verschiedene Sinne von "vorher" zu verschmelzen.

Klassen werden in der Reihenfolge geladen, in der sie verwendet werden. Dies ist zeitlich und ist die korrekte Verwendung von "vorher". Wenn Foo vor Bar verwendet wird, wird es vor Bar geladen.

Sie sprechen auch darüber, ob Klassen/com/acme/Bunny.class "vor" acme.jars com/acme/Bunny.class geladen wird. Der zweite wird überhaupt nicht geladen. Der Classloader sucht nach der ersten Instanz von com/acme/Bunny.class im Klassenpfad, sucht den Klassennamen und hört auf zu suchen.

+0

Ich denke, die Absicht des OP war zu bedeuten, "welche Klasse wird dauern Vorrang "statt" in welcher Reihenfolge werden meine Klassen geladen ". @SpoonBender: Korrigiere mich, wenn ich falsch liege! In jedem Fall ist das erwartete Verhalten, dass die erste "com.acme.Bunny" -Klasse auf dem Klassenpfad geladen wird und alle "com.acme.Bunny" -Klassen weiter unten im Klassenpfad ignoriert werden. Es ist jedoch Sache des Containers, zu entscheiden, was der Klassenpfad ist (und möglicherweise nicht der Umgebungsvariable "CLASSPATH" entspricht). Verschiedene Container können eine andere Suchreihenfolge verwenden. –

+0

@Cameron Er sagte explizit "Aber was ist mit der Reihenfolge, in der die beiden Klassen in den obigen Beispielen geladen sind?" Die Antwort ist "nur einer ist geladen". Danke für die Info über verschiedene Container mit verschiedenen Bestellungen. Der Servlet-Container, den ich verwendet habe, verwendete die Standard-Klassenpfad-Reihenfolge, und ich nahm an, dass alle Container so sinnvoll wären. :-) –

+0

Fair genug. Ich interpretierte es als "in welcher Reihenfolge die Suche durchgeführt wird", einfach weil ich weiß, dass nur eine geladen ist, aber Ihre Interpretation ist mindestens so gut. Kein Container ist völlig vernünftig :) –

1

Die Antwort hängt vollständig von der konkreten Klassenladerhierarchie ab, die verwendet wird. Während die JVM einen Systemklassenlader bereitstellt, verwenden Java EE-Anwendungsserver normalerweise benutzerdefinierte ClassLoader-Implementierungen, um in separaten Modulen und Anwendungen geladene Klassen zu isolieren und Sicherheitsbedenken durchzusetzen.

Die ClassLoader-API schreibt keine Regeln vor, wie konkrete Implementierungen Klassenanforderungen auflösen. Die Absicht des WEB-INF/lib-Verzeichnisses soll jedoch bundling of app-specific libraries ermöglichen. Ich vermute, die meisten Leute würden erwarten, dass die JAR-Dateien im Verzeichnis lib nach dem Root-Inhalt der JAR-Datei durchsucht werden.

Ich bin mir nicht bewusst, dass die Java EE-Spezifikationen eine solche Garantie obwohl, und die Schnittstelle und Dokumentation für die abstrakte Klasse ClassLoader sicherlich nicht.

So hypothetisch könnten Sie einen Web-Container haben, der Bunny.class aus der JAR-Datei statt desjenigen aus der Stammhierarchie der WAR-Datei zurückgeben würde.

1

Es hängt von dem Container ab, der die WAR-Datei bereitstellt. Nach meinen Erfahrungen befindet sich WEB-INF/classes location immer vor lib/auf dem Klassenpfad eines Classloaders für den Anwendungskontext.

Klassen werden geladen, unmittelbar nachdem der Deployer den Krieg in den Container erweitert hat. Normalerweise, wenn ein Context Loader Listener-Servlet geladen wird und der Rest der Anwendung damit. Dies kann auf viele Arten geschehen, beispielsweise durch einen Verweis auf das Standard-Servlet oder den Ladefederkontext usw.

So dass WEB-INF/Klassen/com/acme/Bunny.class zuerst afaik geladen werden sollte.

2

Die Dateien WEB-INF/lib/*.jar und WEB-INF/classes befinden sich im selben ClassLoader. Es wäre so, als ob Sie eine Anwendung mit allen im ClassPath aufgelisteten Gläsern gestartet hätten. Wenn ein Klassenname aufgelöst werden muss, findet der ClassLoader die erste Klasse, die mit seinen Ressourcen übereinstimmt. Die genaue Reihenfolge, in der es sucht, ist nicht deterministisch - es hängt von der Plattform ab.

Java-Pakete wurden entwickelt, um das Problem von Namenskonflikten wie dem, was Sie beschrieben haben, zu beheben. Es ist nie eine gute Idee, eine Klasse genau so zu benennen, wie sie in einer eigenen JAR-Datei enthalten ist. Die bessere Lösung wäre, die Klasse zu erweitern und die neue Version in Ihrem Code zu verwenden. Wenn Sie die Funktionalität dieser Klasse ändern müssen, dann könnten Sie in die schwarze Magie von Java Aspect Oriented Programming schauen.

5

Die ausgewählte Antwort ist falsch. Servlet-Spezifikation Version 2.4 und 3.0 stellen klar, dass WEB-INF/classes geladen wird und dann WEB-INF/lib

Servlet 2.4: http://download.oracle.com/otn-pub/jcp/servlet-2.4-fr-spec-oth-JSpec/servlet-2_4-fr-spec.pdf - Abschnitt SRV.9.5 letzten Absatz

Servlet 3.0: http://download.oracle.com/otn-pub/jcp/servlet-3.0-fr-oth-JSpec/servlet-3_0-final-spec.pdf - Abschnitt 10.5, letzter Absatz

Der Klassenladeprogramm für Webanwendungen muss zuerst Klassen aus dem Verzeichnis WEB-INF/classes laden und dann aus Bibliotheks-JARs im Verzeichnis WEB-INF/lib.

+0

Einverstanden. Die Spezifikation ist klar, obwohl ihre Wortlichkeit es schwierig macht, sie zu finden. – sbk

Verwandte Themen