Domanda

Come si modifica CLASSPATH di un processo Java dall'interno del processo Java?


Prima di chiedermelo " Perché dovresti farlo? " Lo spiegherò tra poco.

  

Quando hai un REPL Clojure in esecuzione è comune avere bisogno di più vasetti nel tuo CLASSPATH per caricare un file sorgente Clojure , e mi piacerebbe farlo senza dover riavviare Clojure stesso (che non è davvero un'opzione quando lo si utilizza su Slime su Emacs).

Questo è il motivo, ma non voglio che questa domanda sia taggata come un editor bizzarro in qualche lingua strana ed essere ignorato dalla maggior parte degli sviluppatori Java che potrebbero avere la risposta.

È stato utile?

Soluzione

Aggiornamento Q4 2017: come commentato sotto di vda8888 , in Java 9, il sistema java.lang.ClassLoader non è più un java.net.URLClassLoader .

Consulta " Guida alla migrazione di Java 9: ??le sette sfide più comuni "

  

La strategia di caricamento della classe che ho appena descritto è implementata in un nuovo tipo e in Java 9 il caricatore della classe di applicazione è di quel tipo.
  Ciò significa che non è più un URLClassLoader , quindi l'occasionale (URLClassLoader) getClass (). GetClassLoader () o (URLClassLoader) ClassLoader.getSystemClassLoader () sequenze non verranno più eseguite.

java.lang.ModuleLayer sarebbe un approccio alternativo usato per influenzare il modulepath (invece del percorso di classe). Vedi ad esempio " Moduli Java 9 - Nozioni di base su JPMS ".


Per Java 8 o versioni precedenti:

Alcuni commenti generali:

non puoi (in un modo portatile che è garantito per funzionare, vedi sotto) cambiare il percorso di classe del sistema. Invece, devi definire un nuovo ClassLoader.

ClassLoader funziona in modo gerarchico ... quindi qualsiasi classe che fa un riferimento statico alla classe X deve essere caricata nello stesso ClassLoader di X o in un ClassLoader figlio. NON è possibile utilizzare alcun ClassLoader personalizzato per creare correttamente il codice caricato dal collegamento ClassLoader di sistema, se non lo avesse mai fatto prima. Quindi è necessario disporre che il codice dell'applicazione principale venga eseguito in ClassLoader personalizzato oltre al codice aggiuntivo che si trova.
(Detto questo, cracked-all menziona nei commenti questo esempio di estendendo il URLClassLoader )

E potresti considerare di non scrivere il tuo ClassLoader, ma usa invece URLClassLoader. Crea un URLClassLoader con un URL non nell'URL dei classloader di classe.

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

Una soluzione più completa sarebbe essere:

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);

Se si assume che il classloader di sistema JVM sia un URLClassLoader (che potrebbe non essere vero per tutte le JVM), è possibile utilizzare anche reflection per modificare effettivamente il percorso di classe del sistema ... (ma è un 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");

Altri suggerimenti

Non credo che tu possa - la cosa giusta da fare (credo) è creare un nuovo classloader con il nuovo percorso. In alternativa, potresti scrivere il tuo classloader che ti consente di cambiare il classpath (per quel caricatore) in modo dinamico.

Potresti voler esaminare usando java.net.URLClassLoader . Ti consente di caricare a livello di codice classi che non erano originariamente nel tuo percorso di classe, anche se non sono sicuro che sia esattamente quello che ti serve.

È possibile come si vede dai due link sottostanti, il metodo offerto da VonC sembra essere il migliore, ma controlla alcuni di questi post e google per "quotazione dinamica di Java" " o " Caricamento della classe dinamica Java " e scopri alcune informazioni da lì.

Pubblicherei in modo più approfondito ma VonC ha praticamente fatto il suo lavoro.

Da Dynamic caricamento di file di classe e Jar .

Controlla anche questo post sul forum di sole .

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

è un esempio di modifica del percorso di classe nel programma java

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top