Вопрос-ответ

How to load JAR files dynamically at Runtime?

Как динамически загружать JAR-файлы во время выполнения?

Почему это так сложно сделать на Java? Если вы хотите иметь какую-либо модульную систему, вам нужно иметь возможность динамически загружать JAR-файлы. Мне сказали, что есть способ сделать это, написав свой собственный ClassLoader, но это большая работа для чего-то, что должно (по крайней мере, на мой взгляд) быть таким же простым, как вызов метода с JAR-файлом в качестве аргумента.

Есть предложения по простому коду, который это делает?

Переведено автоматически
Ответ 1

Причина, по которой это сложно, - безопасность. Загрузчики классов должны быть неизменяемыми; вы не должны иметь возможности волей-неволей добавлять к ним классы во время выполнения. На самом деле я очень удивлен, что это работает с системным загрузчиком классов. Вот как вы это делаете, создавая свой собственный дочерний загрузчик классов:

URLClassLoader child = new URLClassLoader(
new URL[] {myJar.toURI().toURL()},
this.getClass().getClassLoader()
);
Class classToLoad = Class.forName("com.MyClass", true, child);
Method method = classToLoad.getDeclaredMethod("myMethod");
Object instance = classToLoad.newInstance();
Object result = method.invoke(instance);

Болезненно, но это так.

Ответ 2

Следующее решение является хакерским, поскольку оно использует отражение для обхода инкапсуляции, но работает безупречно:

File file = ...
URL url = file.toURI().toURL();

URLClassLoader classLoader = (URLClassLoader)ClassLoader.getSystemClassLoader();
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
method.setAccessible(true);
method.invoke(classLoader, url);
Ответ 3

Хотя большинство перечисленных здесь решений являются либо взломами (до JDK 9), которые сложно настроить (агенты), либо просто больше не работают (после JDK 9) Я нахожу действительно удивительным, что никто не упомянул четко документированный метод.

Вы можете создать пользовательский системный загрузчик классов, а затем вольны делать все, что пожелаете. Отражение не требуется, и все классы используют один и тот же загрузчик классов.

При запуске JVM добавьте этот флаг:

java -Djava.system.class.loader=com.example.MyCustomClassLoader

У classloader должен быть конструктор, принимающий classloader, который должен быть установлен в качестве родительского. Конструктор будет вызван при запуске JVM и будет передан реальный системный загрузчик классов, основной класс будет загружен пользовательским загрузчиком.

Чтобы добавить jar-файлы, просто вызовите ClassLoader.getSystemClassLoader() и приведите его к своему классу.

Ознакомьтесь с этой реализацией для получения тщательно разработанного загрузчика классов. Пожалуйста, обратите внимание, что вы можете изменить add() метод на public .

Ответ 4

Вам следует взглянуть на OSGi, например, реализованный в платформе Eclipse. Он делает именно это. Вы можете устанавливать, деинсталлировать, запускать и останавливать так называемые пакеты, которые фактически являются файлами JAR. Но это делает немного больше, поскольку предлагает, например, сервисы, которые могут быть динамически обнаружены в файлах JAR во время выполнения.

Или посмотрите спецификацию для Java Module System.

java jar