问题
Until java9 for adding external jar to classpath in runtime by programmatically everybody used:
URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod(\"addURL\", new Class[]{URL.class});
method.invoke(sysloader, new Object[]{file.toURI().toURL()});
Now with java9 we have problem:
Exception in thread \"main\" java.lang.ClassCastException: java.base/jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to java.base/java.net.URLClassLoader
URLClassLoader
doesn\'t work anymore in Java 9. What to do now under jdk9 for adding an external jar to the classpath in runtime programmatically?
回答1:
The JavaSE9 release notes read about the same :
The application class loader is no longer an instance of
java.net.URLClassLoader
(an implementation detail that was never specified in previous releases).Code that assumes that ClassLoader::getSytemClassLoader returns a
URLClassLoader
object will need to be updated.Note that Java SE and the JDK do not provide an API for applications or libraries to dynamically augment the class path at run-time.
Additionally when an extended classpath is required, one can make use of
Class<?> clazz = Class.forName("nameofclass", true, new URLClassLoader(urlarrayofextrajarsordirs));
as suggested in this thread from Oracle. This comes with caveats:
java.util.ServiceLoader
uses the thread's ClassLoader context Thread.currentThread().setContextClassLoader(specialloader);
java.sql.DriverManager
does honors the calling class' ClassLoader, -not- the Thread's ClassLoader. Create Driver directly usingClass.forName("drivername", true, new URLClassLoader(urlarrayofextrajarsordirs).newInstance();
javax.activation
uses the thread's ClassLoader context (important for javax.mail).
回答2:
Naman's answer is not a correct replacement for what you are looking for.
The correct way to add a jar to the classpath in Java 9 and above is to use Java Instrumentation's appendToSystemClassLoaderSearch(JarFile jarfile)
method.
First you will need to add your Agent class to your MANIFEST.MF
Launcher-Agent-Class: com.yourpackage.Agent
Then add your agent.
The example below will allow you to call Agent.addClassPath(File f)
to add a Jar to the classpath in both Java 8 & 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(); }
}
}
来源:https://stackoverflow.com/questions/48041764/add-jar-to-classpath-at-runtime-under-java-9