Frage

Wie ändern Sie den Klassenpfad eines Java -Prozesses aus dem Java -Prozess?


Bevor du mich fragst: "Warum willst du das tun?" Ich werde es in Kürze erklären.

Wenn Sie eine Clojure -Repl -Leitung haben, ist es üblich, mehr Gläser in Ihrem Klassenpfad zu benötigen, um a zu laden Clojure Quelldatei, und ich würde es gerne tun, ohne die Clojure selbst neu starten zu müssen (was nicht wirklich eine Option ist, wenn ich sie auf Slime auf EMACs verwendete).

Das ist der Grund, aber ich möchte nicht, dass diese Frage mit einem gewissen Sprachen mit einem gewissen Eduor gekennzeichnet ist und von der Mehrheit der Java-Entwickler, die möglicherweise die Antwort haben, ignoriert werden.

War es hilfreich?

Lösung

Update Q4 2017: als kommentiert unten nach VDA8888, in Java 9 das System java.lang.ClassLoader ist nicht mehr ein java.net.URLClassLoader.

Sehen "Java 9 Migration Guide: Die sieben häufigsten Herausforderungen"

Die gerade beschriebene Klassenladestrategie ist in einem neuen Typ implementiert und in Java 9 ist der Anwendungsklassenlader dieser Art.
Das heißt, es ist nicht ein URLClassLoader mehr, also gelegentlich (URLClassLoader) getClass().getClassLoader() oder (URLClassLoader) ClassLoader.getSystemClassLoader() Sequenzen werden nicht mehr ausgeführt.

java.lang.modulelayer wäre ein alternativer Ansatz, der verwendet wird, um die zu beeinflussen Modulepath (anstelle des Klassenpfads). Siehe zum Beispiel "Java 9 Module - JPMS -Grundlagen".


Für Java 8 oder unten:

Einige allgemeine Kommentare:

Sie können nicht (auf tragbare Weise, die garantiert funktionieren, siehe unten) den Systemklassenpfad ändern. Stattdessen müssen Sie einen neuen Klassenloader definieren.

Klassenloader arbeiten hierarchisch ... Daher muss jede Klasse, die einen statischen Verweis auf Klasse X macht, im selben Klassenloader wie X oder in einem Kinderklassenloader geladen werden. Sie können keinen benutzerdefinierten Klassenloader verwenden, um den Code, der vom System Classloader -Link geladen wird, ordnungsgemäß geladen wird, wenn dies vorher nicht geschehen wäre. Sie müssen also veranlassen, dass Ihr Hauptantragscode zusätzlich zu dem von Ihnen gefundenen zusätzlichen Code im benutzerdefinierten Klassenloader ausgeführt wird.
(Das heißt, das heißt, gar geknackt erwähnt in den Kommentaren dieses Beispiel von Erweiterung der URLClassLoader)

Und Sie werden vielleicht in Betracht ziehen, Ihren eigenen Klassenloader nicht zu schreiben, sondern stattdessen nur einen URLClassloader zu verwenden. Erstellen Sie einen URLClassloader mit einer URL, die es ist nicht in den übergeordneten Klassenladern -URLs.

URL[] url={new URL("file://foo")};
URLClassLoader loader = new URLClassLoader(url);

EIN Vollständige Lösung wäre:

ClassLoader currentThreadClassLoader
 = Thread.currentThread().getContextClassLoader();

// Add the conf dir to the classpath
// Chain the current thread classloader
URLClassLoader urlClassLoader
 = new URLClassLoader(new URL[]{new File("mtFile").toURL()},
                      currentThreadClassLoader);

// Replace the thread classloader - assumes
// you have permissions to do so
Thread.currentThread().setContextClassLoader(urlClassLoader);

Wenn Sie davon ausgehen, dass der JVMS -Systemklasseloader ein URLCASSOLOADER ist (der möglicherweise nicht für alle JVMS zutrifft), können Sie auch die Reflexion verwenden, um den Systemklassenpfad tatsächlich zu ändern ... (aber das ist ein Hack;)):

public void addURL(URL url) throws Exception {
  URLClassLoader classLoader
         = (URLClassLoader) ClassLoader.getSystemClassLoader();
  Class clazz= URLClassLoader.class;

  // Use reflection
  Method method= clazz.getDeclaredMethod("addURL", new Class[] { URL.class });
  method.setAccessible(true);
  method.invoke(classLoader, new Object[] { url });
}

addURL(new File("conf").toURL());

// This should work now!
Thread.currentThread().getContextClassLoader().getResourceAsStream("context.xml");

Andere Tipps

Ich glaube nicht, dass Sie können - das Richtige (ich glaube) ist, einen neuen Klassenloader mit dem neuen Weg zu erstellen. Alternativ können Sie Ihren eigenen Klassenloader schreiben, mit dem Sie den Klassenpfad (für diesen Loader) dynamisch ändern können.

Es ist nicht erforderlich, Ihren eigenen Klassenlader zu schreiben! Es gibt Clojure.lang.DynamicClassloader.

http://blog.japila.pl/2011/01/dynamical-redefining-classpath-in-clojure-repl/

Möglicherweise möchten Sie sich untersuchen java.net.urlclassloader. Sie können programmgesteuert Klassen laden, die ursprünglich nicht in Ihrem Klassenpfad waren, obwohl ich nicht sicher bin, ob genau das ist, was Sie brauchen.

Wie aus den beiden unten stehenden Links ersichtlich ist, scheint die von VONC angegebene Methode die beste zu sein. Schauen Sie sich jedoch einige dieser Beiträge und Google für "Java Dynamic ClassPath" oder "Java Dynamic Class Loading" an und finden Sie einige Informationen von dort heraus.

Ich würde ausführlicher posten, aber vonc hat den Job so ziemlich erledigt.

Aus Dynamisches Laden von Klassen- und JAR -Dateien.

Überprüfen Sie auch das Sun Forum Post.

String s="java  -classpath abcd/ "+pgmname+" "+filename;   
Process pro2 = Runtime.getRuntime().exec(s); 
BufferedReader in = new BufferedReader(new InputStreamReader(pro2.getInputStream()));

ist ein Beispiel dafür, den Klassenpfad im Java -Programm zu verändern

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top