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
risposta
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.
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.
Ama il semplice sforzo sperimentale coinvolto in questa risposta! – Stewart
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:///"));
}
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.
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
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à. –
- 1. Aggiunta di file a classpath java in fase di esecuzione
- 2. Caricamento giare in fase di esecuzione
- 3. Imposta cartella per classpath
- 4. Esecuzione del codice java compilato in fase di esecuzione
- 5. Aggiungere, modificare, rimuovere sederi.schedule in fase di esecuzione
- 6. Aggiunta di annotazioni Java in fase di esecuzione
- 7. Eclipse non compila gli script Groovy in classi java in fase di esecuzione
- 8. Compilazione classe Groovy in fase di esecuzione in Java
- 9. Aggiungi percorso cammello in fase di esecuzione in Java
- 10. Come cambiare lingua in fase di esecuzione in java swing
- 11. Pericoli dell'utilizzo di reflection per aggiungere file a classpath in fase di esecuzione
- 12. Rimuovere la voce da classpath dopo la compilazione
- 13. Modifica implementazione/classe in fase di esecuzione
- 14. scansione java classpath nel plug-in maven
- 15. Eclipse: aggiunta di tutti i jar da una cartella nel classpath java
- 16. Aumenta disposizione PySpark in fase di esecuzione
- 17. Ottieni valori enum da web.config in fase di esecuzione
- 18. Estendere o aggiungere nuove classi in fase di esecuzione in Java
- 19. ClassNotFoundException in fase di esecuzione, ma l'applicazione compila
- 20. Ottieni binding IIS in fase di esecuzione
- 21. Aggiungere animazione in fase di esecuzione
- 22. Modifica codice groovy in fase di esecuzione nell'applicazione Grails
- 23. Come aggiungere una cartella in classpath per lo script ant?
- 24. scegliere una monade in fase di esecuzione
- 25. esclusione in fase di esecuzione __setattr__
- 26. Carica e scarica javascript in fase di esecuzione
- 27. Impostazione tipo generico in fase di esecuzione
- 28. Modifica proprietà log4j in fase di esecuzione
- 29. Modifiche al vtable in fase di esecuzione
- 30. Sostituisci bean in fase di esecuzione
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" ... –
Vorrei sapere se c'è qualsiasi scenario di vita reale per questo requisito. – mks
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