Добавить jar в classpath во время выполнения под java 9
До java9 для добавления внешней банки для пути к классам во время выполнения программным способом:
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 для добавления внешнего бана в путь к классам во время выполнения программно?
Ответы
Ответ 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).
Ответ 2
Наман ответ не является правильной заменой того, что вы ищете. Правильный способ добавить jar в путь к классам в Java 9 и выше - использовать appendToSystemClassLoaderSearch(JarFile jarfile)
Java Instrumentation.
Сначала вам нужно будет добавить класс агента в ваш файл MANIFEST.MF.
Launcher-Agent-Class: com.yourpackage.Agent
Затем добавьте свой агент. Приведенный ниже пример позволит вам вызвать Agent.addClassPath(File f)
чтобы добавить Jar- Agent.addClassPath(File f)
в classpath в 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(); }
}
}