Добавить jar в classpath во время выполнения под java 9
До java9 для добавления внешнего jar в classpath во время выполнения программно все использовали:
URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
method.invoke(sysloader, new Object[]{file.toURI().toURL()});
Теперь с java9 у нас проблема:
Исключение в потоке "main" java.lang.ClassCastException: java.base/jdk.internal.loader.ClassLoaders$AppClassLoader нельзя преобразовать в java.base/java.net.URLClassLoader
URLClassLoader
больше не работает в Java 9. Что теперь делать под jdk9 для программного добавления внешнего jar-файла в classpath во время выполнения?
1 ответ
Примечания к выпуску JavaSE9 читаются примерно так же:
Загрузчик класса приложения больше не является экземпляром
java.net.URLClassLoader
(деталь реализации, которая никогда не была указана в предыдущих выпусках).Код, который предполагает, что
ClassLoader::getSytemClassLoader
возвращаетURLClassLoader
объект нужно будет обновить.Обратите внимание, что Java SE и JDK не предоставляют API для приложений или библиотек для динамического расширения пути к классам во время выполнения.
Кроме того, когда требуется расширенный путь к классу, можно использовать
Class<?> clazz = Class.forName("nameofclass", true, new URLClassLoader(urlarrayofextrajarsordirs));
как предложено в этой теме от Oracle. Это идет с оговорками:
java.util.ServiceLoader
использует контекстный поток ClassLoader Thread.currentThread().setContextClassLoader(specialloader);
java.sql.DriverManager
учитывает вызывающий класс ClassLoader, а не ClassLoader потока. Создать драйвер напрямую, используяClass.forName("drivername", true, new URLClassLoader(urlarrayofextrajarsordirs).newInstance();
javax.activation
использует контекст ClassLoader потока (важно для javax.mail).
Ответ Намана не является правильной заменой тому, что вы ищете. Правильный способ добавить баночку к классам в Java 9 и выше является использование Java - измерительных приборов"ю.ш.appendToSystemClassLoaderSearch(JarFile jarfile)
метод.
Сначала вам нужно добавить свой класс Agent в ваш MANIFEST.MF
Launcher-Agent-Class: com.yourpackage.Agent
Затем добавьте своего агента. Пример ниже позволит вам позвонитьAgent.addClassPath(File f)
чтобы добавить Jar в путь к классам как в 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(); }
}
}