2016-01-07 18 views
7

Esiste un modo per rimuovere una cartella dal percorso di classe simile ad aggiungere una cartella in fase di esecuzione (Can a directory be added to the class path at runtime?)cartella Rimuovere da Java classpath in fase di esecuzione

+1

Hai provato qualcosa? Parte di essere un buon sviluppatore sta avendo il desiderio di sperimentare e capire le cose per te stesso. Non c'è niente di sbagliato nel chiedere, ma questa sarebbe una domanda molto migliore se dovessi iniziare con "Ecco cosa ho provato finora, ma non ha funzionato" ... –

+2

Vorrei sapere se c'è qualsiasi scenario di vita reale per questo requisito. – mks

+1

Non ho provato niente da solo, più semplicemente scavando intorno a possibili soluzioni.Per quanto riguarda gli scenari di vita reale, non posso darti uno scenario di produzione, in quanto verrebbe utilizzato solo nei nostri ambienti di test. – jpints14

risposta

0

Non penso che ci sia un modo dritto in avanti per farlo. È possibile seguire:

  • Ottenere le variabili del percorso di classe utilizzando: System.getenv("CLASSPATH"). Restituirà valori separati da due punti.

    String classPath = System.getenv("CLASSPATH")

  • Prendere il percorso della cartella come input e sostituirlo con "" come:

    String remainigPath = classPath.replace(inputpath,"");

  • Mettere i percorsi rimanenti in un array utilizzando il metodo di divisione.

    String[] paths = remainigPath .split(";");

  • Per aggiungere classPath, hai già il codice.

5

Si prega di trovare sotto uno snippet come esempio tecnico per dimostrare l'aggiunta/rimozione di un percorso.

creare seguenti file di origine in qualsiasi directory

import java.io.File; 
import java.lang.reflect.Field; 
import java.lang.reflect.Method; 
import java.net.URL; 
import java.net.URLClassLoader; 
import java.util.Stack; 
import sun.misc.URLClassPath; 

public class EvilPathDemo { 

    public static void addPath(String path) throws Exception { 
     URL u = new File(path).toURI().toURL(); 
     URLClassLoader urlClassLoader = (URLClassLoader) 
      ClassLoader.getSystemClassLoader(); 
     Class<?> urlClass = URLClassLoader.class; 
     Method method = urlClass.getDeclaredMethod("addURL", 
       new Class[]{URL.class} 
     ); 
     method.setAccessible(true); 
     method.invoke(urlClassLoader, new Object[]{u}); 
    } 

    public static void removePath(String path) throws Exception { 
     URL url = new File(path).toURI().toURL(); 
     URLClassLoader urlClassLoader = (URLClassLoader) 
      ClassLoader.getSystemClassLoader(); 
     Class<?> urlClass = URLClassLoader.class; 
     Field ucpField = urlClass.getDeclaredField("ucp"); 
     ucpField.setAccessible(true); 
     URLClassPath ucp = (URLClassPath) ucpField.get(urlClassLoader); 
     Class<?> ucpClass = URLClassPath.class; 
     Field urlsField = ucpClass.getDeclaredField("urls"); 
     urlsField.setAccessible(true); 
     Stack urls = (Stack) urlsField.get(ucp); 
     urls.remove(url); 
    } 

    public static void main(String[] args) throws Exception { 
     String parm = args.length == 1 ? args[0] : ""; 
     String evilPath = "/tmp"; 

     String classpath = System.getProperty("java.class.path"); 
     boolean isEvilPathSet = false; 
     for (String path : classpath.split(File.pathSeparator)) { 
      if (path.equalsIgnoreCase(evilPath)) { 
       System.out.printf("evil path '%s' in classpath%n", evilPath); 
       isEvilPathSet = true; 
       break; 
      } 
     } 
     if (isEvilPathSet && parm.equalsIgnoreCase("REMOVE")) { 
      System.out.printf("evil path '%s' will be removed%n", evilPath); 
      removePath(evilPath); 
     } 
     tryToLoad("Foo"); 
     if (parm.equalsIgnoreCase("ADD")) { 
      System.out.printf("evil path '%s' will be added%n", evilPath); 
      addPath(evilPath); 
     } 
     tryToLoad("Bar"); 
    } 

    private static void tryToLoad(String className) { 
     try { 
      Class<?> foo = Class.forName(className); 
      System.out.printf("class loaded: %s%n", foo.getName()); 
     } catch (ClassNotFoundException ex) { 
      System.out.println(ex); 
     } 
    } 
} 

.

public class Foo { 
    static { 
     System.out.println("I'm foo..."); 
    } 
} 

.

public class Bar { 
    static { 
     System.out.println("I'm bar..."); 
    } 
} 

compilare loro come seguire

javac EvilPathDemo.java 
javac -d /tmp Foo.java Bar.java 

Durante il test cercheremo di caricare le classi Foo e Bar.

senza/tmp nel percorso classe

java -cp . EvilPathDemo 
java.lang.ClassNotFoundException: Foo 
java.lang.ClassNotFoundException: Bar 

aggiungendo/tmp al classpath

java -cp . EvilPathDemo add 
java.lang.ClassNotFoundException: Foo 
evil path '/tmp' will be added 
I'm bar... 
class loaded: Bar 

con/tmp nel percorso classe

java -cp .:/tmp EvilPathDemo 
evil path '/tmp' in the classpath 
I'm foo... 
class loaded: Foo 
I'm bar... 
class loaded: Bar 

rimuovere/tmp dal classpath

java -cp .:/tmp EvilPathDemo remove 
evil path '/tmp' in the classpath 
evil path '/tmp' will be removed 
java.lang.ClassNotFoundException: Foo 
java.lang.ClassNotFoundException: Bar 

Durante i test ho scoperto che casi seguenti non funzionano.

  • addPath (evilPath);
    tryToLoad ("Foo");
    removePath (evilPath); // non ha avuto effetto
    tryToLoad ("Bar");
  • removePath (evilPath);
    tryToLoad ("Foo");
    addPath (evilPath); // non ha avuto effetto
    tryToLoad ("Bar");
  • tryToLoad ("Foo");
    removePath (evilPath); // non ha avuto effetto
    tryToLoad ("Bar");

Non ho speso tempo per scoprire perché. Perché non vedo alcun uso pratico in esso. Se hai davvero bisogno/desideri giocare con i classpath, guarda come funzionano i classloader.

+1

Ama il semplice sforzo sperimentale coinvolto in questa risposta! – Stewart

4

Il metodo removePath non funzionava per me e il mio contenitore di saldatura, lo stack di url era sempre emtpy. Il seguente metodo smugly brutto lavorato:

public static void removeLastClasspathEntry() throws Exception { 
    URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); 
    Class<?> urlClass = URLClassLoader.class; 
    Field ucpField = urlClass.getDeclaredField("ucp"); 
    ucpField.setAccessible(true); 
    URLClassPath ucp = (URLClassPath) ucpField.get(urlClassLoader); 

    Field loadersField = URLClassPath.class.getDeclaredField("loaders"); 
    loadersField.setAccessible(true); 
    List jarEntries = (List) loadersField.get(ucp); 
    jarEntries.remove(jarEntries.size() - 1); 

    Field pathField = URLClassPath.class.getDeclaredField("path"); 
    pathField.setAccessible(true); 
    List pathList = (List) pathField.get(ucp); 
    URL jarUrl = (URL) pathList.get(pathList.size() - 1); 
    String jarName = jarUrl.toString(); 
    pathList.remove(pathList.size() - 1); 

    Field lmapField = URLClassPath.class.getDeclaredField("lmap"); 
    lmapField.setAccessible(true); 
    Map lmapMap = (Map) lmapField.get(ucp); 
    lmapMap.remove(jarName.replaceFirst("file:/", "file:///")); 
} 
1

caricatori di classe possono essere annidati così invece di modificare il caricatore di classe sistema che è la radice dell'albero di caricatori di classe, è preferibile creare semplicemente un classloader nidificata e uso quello per caricare le classi.

Il classloader di sistema in sé è immutabile (per validi motivi) ma è possibile eseguire ciò che si desidera nei programmi di caricamento classe nidificati, incluso distruggerli per scaricare classi e risorse. Questo è comunemente usato in es. osgi e server delle applicazioni per caricare/scaricare ad es. plug-in, applicazioni, ecc.

Per i caricatori di classe nidificati è possibile personalizzare completamente il modo in cui caricare le classi. Il URLClassloader è probabilmente un buon punto di partenza per quello che vuoi.

0

Ho avuto lo stesso problema, quindi ho affrontato con la creazione di una biblioteca che funziona su ogni ClassLoader che utilizza un URLClassPath (quindi, attualmente, URLClassLoader).

La biblioteca dispone di metodi per:

  • L'aggiunta di nuove voci di fronte
  • Aggiunta di nuove voci
  • Rimuovere le voci esistenti

prega di notare che, dal momento che questa biblioteca accessi interni e di proprietà API, non è garantito il funzionamento nelle versioni future di JDK. Attualmente funziona per Java 7 e Java 8 (Oracle e OpenJDK).

Ecco the GitHub page (contributo è apprezzato), e qui è the Maven Central artifact

+0

Solo una nota: il codice è ispirato ai frammenti trovati qui da [JohannSchwarz] (http://stackoverflow.com/users/1979735/johannschwarz) e [SubOptimal] (http://stackoverflow.com/users/2333222/ subottimale), con alcune modifiche che dovrebbero (marginalmente, in realtà) migliorare l'affidabilità. –

Problemi correlati