¿Cómo se cambia CLASSPATH en Java?

¿Cómo se cambia la CLASSPATH de un proceso Java desde el proceso de Java?


Antes de que me preguntes “¿Por qué querrías hacer eso?” Lo explicaré en breve.

Cuando ejecuta Clojure REPL es común que necesite más jar en CLASSPATH para cargar un archivo fuente de Clojure , y me gustaría hacerlo sin tener que reiniciar Clojure (lo cual no es realmente una opción cuando lo usa en Slime). en Emacs).

Esa es la razón, pero no quiero que esta pregunta sea etiquetada como algún extraño editor de lenguaje raro y que la mayoría de los desarrolladores de Java que no responden lo descarten.

Actualización del cuarto trimestre de 2017: como se comenta más abajo en vda8888 , en Java 9, el sistema java.lang.ClassLoader ya no es un java.net.URLClassLoader .

Consulte ” Guía de migración de Java 9: ​​los siete desafíos más comunes ”

La estrategia de carga de clases que acabo de describir se implementa en un nuevo tipo y en Java 9 el cargador de clases de aplicaciones es de ese tipo.
Eso significa que ya no es un URLClassLoader , por lo que las (URLClassLoader) getClass().getClassLoader() ocasionales (URLClassLoader) getClass().getClassLoader() o (URLClassLoader) ClassLoader.getSystemClassLoader() ya no se ejecutarán.

java.lang.ModuleLayer sería un enfoque alternativo utilizado para influir en la ruta del módulo (en lugar de la ruta de clases). Ver por ejemplo ” Módulos de Java 9 – Conceptos básicos de JPMS “.


Para Java 8 o abajo:

Algunos comentarios generales:

no se puede (de una manera portátil, está garantizado que funcione, ver a continuación) cambiar el classpath del sistema. En su lugar, debe definir un nuevo ClassLoader.

Los ClassLoaders funcionan de manera jerárquica … por lo que cualquier clase que haga una referencia estática a la clase X debe cargarse en el mismo ClassLoader como X, o en un ClassLoader secundario. NO puede usar ningún ClassLoader personalizado para cargar correctamente el código del enlace del ClassLoader del sistema, si no lo hubiera hecho antes. Por lo tanto, debe organizar que el código de la aplicación principal se ejecute en el ClassLoader personalizado además del código adicional que localice.
(Dicho esto, agrietado, todos mencionan en los comentarios este ejemplo de extender el URLClassLoader )

Y podría considerar no escribir su propio ClassLoader, sino simplemente usar URLClassLoader. Cree un URLClassLoader con una url que no esté en las URL de los cargadores de clase padre.

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

Una solución más completa sería:

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

Si supone que el cargador de clases del sistema JVM es un URLClassLoader (que puede no ser cierto para todas las JVM), también puede usar la reflexión para modificar realmente la ruta de clase del sistema … (pero eso es un truco;)):

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

No creo que puedas: lo correcto (creo) es crear un nuevo cargador de clases con la nueva ruta. Alternativamente, podría escribir su propio cargador de clases que le permita cambiar el classpath (para ese cargador) dinámicamente.

¡No es necesario que escriba su propio cargador de clases! Hay clojure.lang.DynamicClassLoader .

http://blog.jastack.pl/2011/01/dynamically-redefining-classpath-in-clojure-repl/

Es posible que desee examinar el uso de java.net.URLClassLoader . Te permite cargar clases programáticamente que no estaban originalmente en tu classpath, aunque no estoy seguro si eso es exactamente lo que necesitas.

Es posible como se ve en los dos enlaces a continuación, el método que VonC da parece ser el mejor, pero eche un vistazo a algunas de estas publicaciones y busque “Java Dynamic Classpath” o “Java Dynamic Class Loading” y descubra alguna información de allí.

Publicaría con más profundidad, pero VonC prácticamente ha hecho el trabajo.

Desde carga dinámica de clase y archivos Jar .

También consulta esta publicación en el foro del sol .

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

es un ejemplo de cambiar el classpath en el progtwig java