Greifen Sie auf statische Methoden von Klassen zu, die von verschiedenen ClassLoaders geladen wurden

9

Ich habe zwei Klassen ( A und B ), die von verschiedenen ClassLoaders geladen werden. Außerdem habe ich eine dritte Klasse, welche Provider statische Getter- und Setter-Methoden verwenden. Ich hoffe folgendes Bild kann die Situation klären:

Die Klasse Data sieht wie folgt aus:

%Vor%

In der Klasse A möchte ich den statischen Wert von Data und in B den Wert abfragen. In B erhalte ich jedoch immer den ursprünglichen Wert (was "<fill in>" ist). Ich habe nur ein grundlegendes Verständnis von ClassLoader s, also bin ich mir nicht sicher, was unter der Haube passiert. Ich dachte, dass beide ClassLoader ( clA und clB ) an ihre Eltern ClassLoader weitergeben werden und dass ich die gleiche Data -Klasse in beiden bekommen werde. Kann mir jemand Feedback zum Verhalten geben oder mich in die Richtung lenken, in die ich schauen kann?

Aktualisieren

Wenn ich die hashCode() der beiden Data Klassen drucke, erhalte ich unterschiedliche Werte für sie (was bedeutet, dass ich offensichtlich nicht auf die gleiche Klasse zugreifen kann). Gibt es eine einfache Möglichkeit, die Hierarchie ClassLoader zu veranschaulichen?

    
WeSt 30.11.2014, 20:59
quelle

2 Antworten

2

Wenn Ihre Frage darin besteht, die Klassenladerhierarchie für Objekte zu veranschaulichen oder zu visualisieren, können Sie jeden Klassenklassenlader im Code durchlaufen. Du hast erwähnt, dass du groovy verwendest, also würde ein Beispiel wie folgt aussehen:

%Vor%

Ich denke, Sie werden feststellen, dass in Ihrem Code die beiden Datenobjekte nicht vom selben Klassenlader geladen werden, weshalb sie verschiedene statische Variablen haben.

Ich habe ein Beispiel zusammengestellt, das

hat
  • Haupt (vom übergeordneten Klassenlader geladen)
  • DataObj mit einem statischen String (auch vom übergeordneten Klassenlader geladen)
  • LoadA, das eine Kopie von DataObj (geladen von Child-Classloader A)
  • instanziiert
  • LoadB, das eine Kopie von DataObj instanziiert (geladen von Child-Classloader B)

Ich sehe, dass, während LoadA und LoadB verschiedene Klassenlader haben, das DataObj und die statische Variable von einem gemeinsamen Klassenlader stammen.

Vollständiger Code unter: Ссылка

Das Hauptobjekt in groovy:

%Vor%

Die Ergebnisse sind:

%Vor%

Sie sehen, dass LoadA und LoadB beide unterschiedliche Klassenlader haben, aber sie teilen sich einen übergeordneten Klassenlader.

Der übergeordnete Klassenlader lädt das DataObj für beide Instanzen von LoadA.dataObj und LoadB.dataObj.

LoadA.dataObj und LoadB.dataObj haben unterschiedliche Hashcodes.

LoadA.dataObj.data und LoadB.dataObj.data haben jedoch denselben Hashcode, da dies das statische Objekt ist. Sie haben auch den gleichen Wert. LoadB instanziiert sein dataObj last und setzt den String auf "Loaded By B"

    
Lucas McGregor 01.07.2015, 06:09
quelle
1

Ich glaube, Lucas hat Ihre Frage beantwortet, um die Hierarchie zu illustrieren. Ich möchte meine Antwort nur hinzufügen, um einige Erinnerungen an die Frage zu klären.

In Java ist das Paar (Klassenloader, Klassenname definierend) eindeutig. Classloader ist hier der Loader, der die Klasse als Klasse aus Bytecode realisiert. Diese Eindeutigkeit bedeutet, dass ein Klassenlader, der die Klasse X definiert, keine zweite Klasse X definieren kann, sondern einen anderen Namen haben muss. Aber ein anderer Klassenlader kann die Klasse definieren. ClassLoaders sind in einer Art Baum strukturiert (es ist nicht wirklich eine DAG, aber das geht hier zu weit) und ein Klassenlader soll seinen Eltern zuerst fragen, ob er nach einer Klasse fragt. So kann es passieren, dass Daten zweimal vorkommen, zum Beispiel einmal in cIA und einmal in cIB. Um dies zu vermeiden, möchten Sie normalerweise, dass Daten von einem Klassenlader definiert werden, der ein Elternteil von cIA und cIB ist. Dies setzt voraus, dass sich die beiden Lader gemäß den Beschränkungen des Klassenladers verhalten, wie zum Beispiel die Eltern zuerst zu fragen.

Da es sich hier auch um ein Groovy-Skript handelt, aber keine genauen Angaben über das Setup gemacht werden, nehme ich an, dass ciB keine Eltern hat, die Data kennen und dass die Bibliothek in die URL des verwendeten GroovyClassLoaders eingegeben wurde und Sie verwendete GroovyShell. Was stattdessen getan werden sollte ist, dass GroovyShell mit einem der Argumente des Klassenladers instanziiert wird und dass dieser Klassenlader ein Kind für den Loader ist, der Data definiert, der auch ein Elternteil für cIA ist (der Vater kann in allen Fällen der gleiche Loader sein) Begriff Elternteil).

Eine Warnung ... GroovyClassLoader ist kein Klassenlader, der sich gut benimmt. Es bevorzugt definierte Klassen (zum Beispiel durch ein Skript) über Klassen vom Elternteil. Wenn Sie ein Skript mit der Klasse Data haben, wird es diese Data-Klasse verwenden, auch wenn das übergeordnete Element normalerweise der definierende Klassenlader ist

    
blackdrag 01.12.2015 23:12
quelle

Tags und Links