Agregue jar a classpath en tiempo de ejecución bajo java 9
java-9 urlclassloader (2)
Hasta java9 para agregar jar externo a classpath en tiempo de ejecución mediante programación, todos usaron:
URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
method.invoke(sysloader, new Object[]{file.toURI().toURL()});
Ahora con java9 tenemos un problema:
Excepción en el hilo "principal" java.lang.ClassCastException: java.base / jdk.internal.loader.ClassLoaders $ AppClassLoader no se puede convertir a java.base / java.net.URLClassLoader
URLClassLoader
ya no funciona en Java 9. ¿Qué hacer ahora bajo jdk9 para agregar un jar externo al classpath en tiempo de ejecución mediante programación?
La respuesta de Naman no es un reemplazo correcto de lo que está buscando.
La forma correcta de agregar un jar al classpath en Java 9 y superior es usar el método
appendToSystemClassLoaderSearch(JarFile jarfile)
Java Instrumentation
.
Primero deberá agregar su clase de Agente a su MANIFEST.MF
Launcher-Agent-Class: com.yourpackage.Agent
Luego agrega tu agente.
El siguiente ejemplo le permitirá llamar a
Agent.addClassPath(File f)
para agregar un Jar al classpath en Java 8 y 9+
public class Agent {
private static Instrumentation inst = null;
// The JRE will call method before launching your main()
public static void agentmain(final String a, final Instrumentation inst) {
Agent.inst = inst;
}
public static boolean addClassPath(File f) {
ClassLoader cl = ClassLoader.getSystemClassLoader();
try {
// If Java 9 or higher use Instrumentation
if (!(cl instanceof URLClassLoader)) {
inst.appendToSystemClassLoaderSearch(new JarFile(f));
return;
}
// If Java 8 or below fallback to old method
Method m = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
m.setAccessible(true);
m.invoke(cl, (Object)f.toURI().toURL());
} catch (Throwable e) { e.printStackTrace(); }
}
}
Las notas de la versión de JavaSE9 leen casi lo mismo:
El cargador de clases de aplicaciones ya no es una instancia de
java.net.URLClassLoader
(un detalle de implementación que nunca se especificó en versiones anteriores).El código que supone que
ClassLoader::getSytemClassLoader
devuelve un objetoURLClassLoader
deberá actualizarse.Tenga en cuenta que Java SE y JDK no proporcionan una API para aplicaciones o bibliotecas para aumentar dinámicamente la ruta de clase en tiempo de ejecución .
Además, cuando se requiere un classpath extendido, uno puede hacer uso de
Class<?> clazz = Class.forName("nameofclass", true, new URLClassLoader(urlarrayofextrajarsordirs));
como se sugiere en este hilo de Oracle . Esto viene con advertencias:
java.util.ServiceLoader
usa el contexto de ClassLoader del hilo Thread.currentThread (). setContextClassLoader (specialloader);
java.sql.DriverManager
hace honor a la clase de llamada ''ClassLoader, -no- el Thread''s ClassLoader. Cree el controlador directamente usandoClass.forName("drivername", true, new URLClassLoader(urlarrayofextrajarsordirs).newInstance();
javax.activation
usa el contexto de ClassLoader del hilo (importante para javax.mail).