2012-05-13 9 views
6

Ich habe zwei verschiedene Webapps, und jede lädt die gleiche Klasse A mit verschiedenen Classloader. Wenn ich eine Instanz in die Sitzung lege und sie dann von der anderen Webanwendung abrufe, wird eine ClassCastException ausgelöst.Wie man zwei Instanzen desselben geladenen unterschiedlichen Klassenladers wirft?

Zum Beispiel in Webapp A, I speichern a in der Sitzung, dann in Webapp B, ich habe die a aus der Sitzung erhalten und es auf einen Darsteller, der ClassCastException geworfen wird.

Gibt es eine Möglichkeit, dies zu beheben?

Antwort

3

Sie sollten diese Situation im Grunde vermeiden - entweder beide Bits der Funktionalität in derselben Webanwendung platzieren oder die Bibliothek mit der Klasse A an eine geeignete Stelle verschieben, so dass nur ein Klassenlader verwendet wird. Zwei Klassen, die von verschiedenen Klassenlatern geladen werden, sind in der JVM völlig unterschiedlich - Sie können einfach nicht zwischen umwandeln.

Weitere Informationen zu den verschiedenen verwendeten Klassenladern finden Sie unter Tomcat classloader documentation. Es sieht so aus, als ob Sie diese allgemeine Klasse in den allgemeinen Classloader-Bereich einfügen möchten. Wie die Dokumentation bemerkt, ist dies ziemlich ungewöhnlich, aber wenn Sie wirklich ein Objekt zwischen zwei Webapps teilen wollen (das ist auch ungewöhnlich), ist es wahrscheinlich der einfachste Weg vorwärts.

5

Gibt es eine Möglichkeit, dies zu lösen?

Grundsätzlich nicht.

Soweit es die JLS betrifft, sind die Typen verschiedene Typen, und es gibt keine Möglichkeit, dass die JVM Ihnen erlauben wird, etwas anderes vorzutäuschen. Zum Beispiel könnten die Klassen unterschiedlichen Code und unterschiedliche Objektlayouts haben. Wenn Sie die JVM dazu bringen könnten, die Typen als gleich zu behandeln, könnten Sie die JVM-Laufzeitsicherheit wegblasen. Auf diese Weise liegt Wahnsinn.

Die Lösung besteht darin, sicherzustellen, dass Sie nicht zwei verschiedene Klassenladeprogramme haben, die dieselbe Klasse laden. Im Kontext von Tomcat bedeutet dies, dass, wenn zwei oder mehr Webapps Instanzen einer Klasse teilen müssen, diese Klasse in einem Klassenlader definiert werden muss, der beiden gemeinsam ist; z.B. Setzen Sie die JAR-Datei in das Verzeichnis $CATALINA_HOME/lib oder $CATALINA_HOME/common.


Wenn es einen guten Grund, warum die Klassen haben von verschiedenen Classloader geladen werden (vielleicht, weil die Klassen wirklich verschieden sind), dann könnte man das Problem umgehen, indem eine Schnittstelle definiert, die beide Versionen des Klasse implementieren und dann auf die Schnittstelle statt auf die Implementierungsklasse programmieren. Natürlich kann nur eine Version dieses Interfaces geladen werden ... sonst laufen Sie wieder auf dasselbe Problem.

1

Sie können nicht. Zwei Klassen, die von verschiedenen Klassenladern geladen werden, sind unterschiedlich.

0

Vielleicht können Sie die gemeinsamen Objekte serialisieren?

Ich bin nicht unbedingt diesen Ansatz befürworten, aber dann wieder das ist, was die Serialisierung im Wesentlichen tut --- Sie von einer JVM oder Classloader serialisiert X und laden Sie es in (deserialize) in eine andere JVM/Classloader Y ...

+0

Ich denke, Serialisierung funktioniert möglicherweise, aber ich benutze schließlich CAS, um dieses Problem zu lösen. :) – xiaolg2008

0

Sie können nicht zwei Objekt aus verschiedenen Klassen selbst gegossen, wenn die Klassen das gleiche Paket Namen und Unterschrift haben, jedoch können Sie die Daten von einem zum anderen kopieren Sie einfach von Apache Bean utils Bibliothek, BeanUtils.copyProperties(o1, o2);

0

Diese ist mit einer Problemumgehung möglich.

Es ist zwar wahr, dass Sie ein Objekt aus einer von Classloader A geladenen Klasse nicht in die gleiche Klasse von Classloader B laden können (Klassen mit demselben Namen sind nicht kompatibel, wenn sie unter verschiedenen Klassenloadern wie explained here geladen sind) Mit einem Webapp-Container wie Jetty oder Tomcat können Sie diese Klasse einmal in einem übergeordneten Classloader laden, der von allen Webapps in der JVM verwendet wird. Jeder webapp classloader wird auf den freigegebenen (übergeordneten) Classloader für die Klassendefinition zurückgreifen und das Hin und Herwerfen funktioniert gut.

Verwenden Sie zum Beispiel mit Jetty WebAppContext.addSystemClass() wie beschrieben here.