java jar classpath java-9 urlclassloader

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 objeto URLClassLoader 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 usando Class.forName("drivername", true, new URLClassLoader(urlarrayofextrajarsordirs).newInstance();

  • javax.activation usa el contexto de ClassLoader del hilo (importante para javax.mail).