2011-10-25 19 views
23

Para comprender mejor cómo funcionan las cosas en Java, me gustaría saber si puedo agregar dinámicamente, en tiempo de ejecución, un directorio a la ruta de la clase.¿Se puede agregar un directorio a la ruta de clase en tiempo de ejecución?

Por ejemplo, si lanzo un .jar usando "java-jar mycp.jar" y la salida de la java.class.path propiedad, que puede conseguir:

java.class.path: '.:/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java' 

Ahora ¿Puedo modificar esta ruta de clase en tiempo de ejecución para agregar otro directorio? (por ejemplo, antes de hacer la primera llamada a una clase usando un .jar ubicado en ese directorio que quiero agregar).

Respuesta

38

Se puede utilizar el siguiente método:

URLClassLoader.addURL(URL url) 

Pero vas a tener que hacer esto con la reflexión ya que el método es protected:

public static void addPath(String s) throws Exception { 
    File f = new File(s); 
    URL u = f.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}); 
} 

Ver el rastro de Java en Reflection . Especialmente la sección Inconvenientes de Reflexión

+0

Realmente muy útil, gracias! –

+0

https://docs.oracle.com/javase/7/docs/api/java/net/URLClassLoader.html –

+0

esto no funciona para mí ... no puedo cargar clases después de esto usando Class.forName (" com.mysql.jdbc.Driver "); –

9

Sí, puede usar URLClassLoader .. ver ejemplo here. No usa el reflejo

- editar -

Copiar el enlace de ejemplo como se sugiere.

import javax.naming.*; 
import java.util.Hashtable; 
import java.net.URLClassLoader; 
import java.net.URL; 
import java.net.MalformedURLException; 

public class ChangeLoader { 

    public static void main(String[] args) throws MalformedURLException { 
    if (args.length != 1) { 
     System.err.println("usage: java ChangeLoader codebase_url"); 
     System.exit(-1); 
    } 

    String url = args[0]; 
    ClassLoader prevCl = Thread.currentThread().getContextClassLoader(); 

    // Create class loader using given codebase 
    // Use prevCl as parent to maintain current visibility 
    ClassLoader urlCl = URLClassLoader.newInstance(new URL[]{new URL(url)}, prevCl); 

     try { 
     // Save class loader so that we can restore later 
      Thread.currentThread().setContextClassLoader(urlCl); 

     // Expect that environment properties are in 
     // application resource file found at "url" 
     Context ctx = new InitialContext(); 

     System.out.println(ctx.lookup("tutorial/report.txt")); 

     // Close context when no longer needed 
     ctx.close(); 
    } catch (NamingException e) { 
     e.printStackTrace(); 
     } finally { 
      // Restore 
      Thread.currentThread().setContextClassLoader(prevCl); 
     } 
    } 
} 
+0

El ejemplo es bueno y evitan el uso de la reflexión. Pero tal vez puedas copiarlos aquí, en caso de que el enlace se rompa? –

+0

@AlexeyGrigorev hecho. – Kashyap

+3

Es genial que esto evite la reflexión, pero tiene un precio: no está agregando una ruta de acceso al classpath de proceso pero creando un nuevo cargador de clases que incluye la nueva ruta y la usa dentro de un hilo concreto, en este caso, su actual hilo. Esto significa que cualquier ruta agregada de esta manera solo se notará en esa cadena con cargadores de clase modificados explícitamente. –

20

Actualización 2014: este es el código de la respuesta aceptada, por Jonathan Spooner a partir de 2011, ligeramente reescrito para tener validadores de Eclipse ya no crean advertencias (depreciación, rawtypes)

//need to do add path to Classpath with reflection since the URLClassLoader.addURL(URL url) method is protected: 
public static void addPath(String s) throws Exception { 
    File f = new File(s); 
    URI u = f.toURI(); 
    URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); 
    Class<URLClassLoader> urlClass = URLClassLoader.class; 
    Method method = urlClass.getDeclaredMethod("addURL", new Class[]{URL.class}); 
    method.setAccessible(true); 
    method.invoke(urlClassLoader, new Object[]{u.toURL()}); 
} 
+2

Hubiera sido más stackoverflowish para editar la respuesta aceptada, creo. No más respuestas duplicadas, eso es lo que nos gusta en este sitio. – Zeemee

+2

@Zeemee Apenas recuerdo, tal vez pensé que este era un caso extremo. Simplemente decidí evitar demasiado la respuesta aceptada; No quería ir más allá de la intención del autor. – knb

Cuestiones relacionadas