Frage

ich ein statisches Analyse-Tool für eine Zuordnung schreibe, analysiert die Java-Bytecode der ASM-Bibliothek. Eines der Teile von ASM, die wir verwenden müssen (oder zumindest zu verlangen, erscheint), dass die Klasse aus dem Classloader geladen werden.

Wir haben gehofft, die Tool-Dateien zu analysieren .class- wäre in der Lage, ohne sie auf dem Classpath zu erfordern. Wir laden bereits die .classes aus einem bestimmten Verzeichnis zur Laufzeit und lesen sie einen Inputstream in Verwendung. Dies ist akzeptabel für ASM in den meisten Fällen. Es gibt einige Klassen, wie SimpleVerifier, die versuchen, obwohl die Klassen zu laden.

Ist es möglich, unter diesem Szenario die .class-Dateien registrieren geladen werden, so dass sie nennt lädt zu Class.forName()? Oder gibt es eine einfache Möglichkeit, die Classloader zu verlängern dies zulassen?


Edit: die Informationen über URLClassLoader war nützlich. Leider hat mit Thread.currentThread().setContextClassLoader() auf eine Instanz, dass in diesem Szenario nicht funktionieren. Die Bibliothek Code Ich rufe in verwendet einen Loader auf Instanz Initialisierung ruft getClass().getClassLoader() verwendet wird.

Als ich die URLClassLoader gesetzt die Klasse nicht initialisiert worden ist, so denke ich, die contextClassLoader nicht, dass die Klasse laden.

Habe ich die Antworten richtig verstanden? Würde die URLClassLoader mit der 3rd-Party-Klasse laden eine Möglichkeit sein?

War es hilfreich?

Lösung

Fast.

Wenn Sie Klassen irgendwo zusammengestellt haben, können Sie sie laden mit URLClassLoader . Anschließend können Sie diese Classloader stellen Sie den Classloader für den aktuellen Thread zu sein: Thread.setContextClassLoader (Classloader)

Die Benutzer können, dass die aktuellen Themen im Kontext Class Loader erhalten und verwenden Sie die Klassendefinition zuzugreifen.

Andere Tipps

Zu allererst ASM kann in einer solchen Art und Weise verwendet werden, dass es nicht Classloader verwenden Informationen über die Klassen zu erhalten.

Es gibt mehrere Orte in ASM Rahmen, in dem es Klassen standardmäßig lädt aber all diese Orte können in Ihren eigenen Unterklassen überschrieben werden. Aus der Spitze von meinem Kopf:

  • ClassWriter.getCommonSuperClass () Methode nur aufgerufen, wenn ClassWriter.COMPUTE_FRAMES Flag verwendet wird und kann overwriten werden, um nicht zu verwenden Classloader inforamtion über Klassen zu erhalten. Sie können ein Beispiel, dass in ClassWriterComputeFramesTest , die eine Abstraktion Class
  • In ähnlicher SimpleVerifier.getClass () -Methode von SimpleVerifier.isAssignableFrom () und Sie können die letztere überschreiben und die Abstraktion Class die häufig finden Super-Typ. Wenn ich mich nicht täusche, hatte AspectWerkz Projekt ähnlich, was in seiner Art Pattern-Matching-Code implementiert. Beachten Sie auch, dass es SimpleVerifier.setClassLoader () Methode, die Sie verwenden können, wenn Sie noch Ihre eigenen Klassen geladen werden soll.

Auf einer Seite zur Kenntnis, auf einem Sun JVMs, bekommen geladene Klassen Bereich PermGen und nicht entladen werden können, so ist es keine gute Idee, Klassen zu laden, nur für statische Code-Analysezwecke, wenn Sie das vermeiden können, vor allem, wenn Werkzeug würde einen langfris Live-Prozess, wie IDE integriert werden.

Sie können nicht, soweit ich weiß, die System-Class-Loader zur Laufzeit verlängern, aber Sie können dynamisch Klassen von einem beliebigen Ort (jar oder Verzeichnis) laden mit URLClassLoader .

Sie können Setup einen Versuch „Launcher“ in der Start Ihrer Anwendung, die es der Standorte vorbei auf dem Classpath und Ihre eigenen URLClassLoader Standorte und starten Sie die Anwendung von diesem Classloader eine .class erstellt.

Wenn die SimpleVerifier durch die URLClassLoader geladen wird, wird es auch in der Lage sein, die Klassen von den zusätzlichen Standorten zu laden.

Ja, können Sie URLClassLoader

Ich habe einen Test, bei dem ich die Klasse zur Laufzeit laden kann. Diese Klasse ist nicht im Classpath (nicht einmal existieren, wenn der Test für diese Angelegenheit ausgeführt wird), später wird es geladen und funktioniert super.

Hier ist der Code.

void testHello() throws MalformedURLException, ClassNotFoundException {
    URL[] url = {
            new URL("file:/home/oreyes/testwork/")
    };

    try {
        new URLClassLoader(url).loadClass("Hello");
        throw new AssertionError("Should've thrown ClassNotFoundException");
    } catch ( ClassNotFoundException cnfe ){}


    c.process();// create the .class file 

    new URLClassLoader(url).loadClass("Hello");

    // it works!!
}

Genommen von dieser Frage .

Ich habe meine eigenen Classloader seine ganz einfach.

 /**
 * Used to hold the bytecode for the class to be loaded.
 */
private final static ThreadLocal<byte[]> BYTE_CODE = new ThreadLocal<byte[]>();

@Override
protected Class<?> findClass(final String name) throws ClassNotFoundException {
    final byte[] bytes = BYTE_CODE.get();
    if (null == bytes) {
        throw new ClassNotFoundException(name);
    }
    return this.defineClass(null, bytes, 0, bytes.length);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top