2009-06-18 49 views
58

¿Es posible agregar un archivo (no necesariamente un archivo jar) a Java classpath en tiempo de ejecución? Específicamente, el archivo ya está presente en el classpath, lo que quiero es si puedo agregar una copia modificada de este archivo al classpath.Agregar archivos a Java classpath en el tiempo de ejecución

Gracias,

+0

¿Existe? e una forma de eliminar un archivo jar? ¿O sustituirlo por una versión más nueva? – dmarrazzo

Respuesta

0

sí, se puede. tendrá que estar en su estructura de paquete en un directorio separado del resto de su código compilado si desea aislarlo. entonces simplemente colocará su directorio base al frente de la ruta de clase en la línea de comando.

0

Sí, creo que es posible, pero es posible que deba implementar su propio cargador de clases. Nunca lo hice, pero ese es el camino que probablemente miraría.

5

Puede probar java.net.URLClassloader con la url de la carpeta/jar donde reside la clase actualizada y usarla en lugar del cargador de clases predeterminado al crear una nueva cadena.

37

Solo puede agregar carpetas o archivos jar a un cargador de clases. Entonces, si tiene un solo archivo de clase, primero debe colocarlo en la estructura de carpetas adecuada.

Here es un corte bastante feo que se suma a la SystemClassLoader en tiempo de ejecución:

import java.io.IOException; 
import java.io.File; 
import java.net.URLClassLoader; 
import java.net.URL; 
import java.lang.reflect.Method; 

public class ClassPathHacker { 

private static final Class[] parameters = new Class[]{URL.class}; 

public static void addFile(String s) throws IOException { 
    File f = new File(s); 
    addFile(f); 
}//end method 

public static void addFile(File f) throws IOException { 
    addURL(f.toURL()); 
}//end method 


public static void addURL(URL u) throws IOException { 

    URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader(); 
    Class sysclass = URLClassLoader.class; 

    try { 
    Method method = sysclass.getDeclaredMethod("addURL", parameters); 
    method.setAccessible(true); 
    method.invoke(sysloader, new Object[]{u}); 
    } catch (Throwable t) { 
    t.printStackTrace(); 
    throw new IOException("Error, could not add URL to system classloader"); 
    }//end try catch 

    }//end method 

}//end class 

La reflexión es necesaria para acceder al método protegido addURL. Esto podría fallar si hay un SecurityManager.

+0

Gracias por la respuesta chicos, supongo que también podemos agregar un archivo simple (no una clase o jar, etc ...) en el classpath, pero ¿cómo sé cuál sería recogido (la última adición es la classpath o el archivo anterior) –

+0

Ah, eso es un problema. Gran parte de esto depende de la implementación, por lo que realmente no debería tener clases (u otros recursos) con el mismo nombre en el mismo cargador de clases. – Thilo

+0

Si los coloca en cargadores de clase separados, entonces hay una especificación. Usualmente el cargador de clases padre toma precendencia, para webapps a veces es al revés (pero aún bien definido). El gestor de arranque siempre es lo primero. – Thilo

32

Prueba este tamaño.

private static void addSoftwareLibrary(File file) throws Exception { 
    Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class}); 
    method.setAccessible(true); 
    method.invoke(ClassLoader.getSystemClassLoader(), new Object[]{file.toURI().toURL()}); 
} 

Esto edita el cargador de clases del sistema para incluir el contenedor de la biblioteca. Es bastante feo, pero funciona.

+0

Great answer.Sin embargo, lo editaría un poco, haciendo uso de varargs para hacerlo aún más simple. –

12

La forma en que he hecho esto es mediante el uso de mi propio cargador de clases

URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); 
DynamicURLClassLoader dynalLoader = new DynamicURLClassLoader(urlClassLoader); 

Y crear la clase siguiente:

public class DynamicURLClassLoader extends URLClassLoader{ 

public DynamicURLClassLoader(URLClassLoader classLoader) { 
    super(classLoader.getURLs()); 

} 

@Override 
public void addURL(URL url) { 
    super.addURL(url); 
} 

} 

obras sin ninguna reflexión

+0

Esta solución me sonaba bien, pero no funciona (¿tal vez porque estoy en una aplicación web de Tomcat?). Obtengo un error de "clase no encontrada" cuando intento llamar a un método de una clase contenida en el JAR cargado dinámicamente. Las otras soluciones funcionan, incluso en una aplicación web. – toni07

+0

Esto no funciona ya que crea un nuevo cargador de clases, los otros cargadores de clases todavía no tendrán acceso al archivo que ha agregado a este cargador de clases – cinqS

-2

Mi solución:

File jarToAdd = new File("/path/to/file"); 

new URLClassLoader(((URLClassLoader) ClassLoader.getSystemClassLoader()).getURLs()) { 
    @Override 
    public void addURL(URL url) { 
     super.addURL(url); 
    } 
}.addURL(jarToAdd.toURI().toURL()); 
+1

Explique qué hace su código (__en la respuesta en sí, no en los comentarios__) además de proporcionarlo . –

+0

Esto no funciona porque el método 'addURL' en' URLClassLoader' está 'protected'. Pero puede escribir su propio URLClassLoader que reescribe el método y el modificador debe ser accesible. – cinqS

Cuestiones relacionadas