Мне нужно добавить функциональность плагина к существующему приложению для определенных частей приложения. Я хочу иметь возможность добавлять банку во время выполнения, и приложение должно иметь возможность загружать класс из jar без перезапуска приложения. Все идет нормально. Я нашел несколько примеров в Интернете с помощью URLClassLoader, и он отлично работает.
Я также хотел, чтобы перезагружать один и тот же класс, когда доступна обновленная версия банки. Я снова нашел несколько примеров и ключ к достижению этого, так как я понимаю, что мне нужно использовать новый экземпляр класса для каждого нового загружаемого файла.
Я написал несколько примеров кода, но попал в исключение NullPointerException. Сначала позвольте мне показать вам код:
package test.misc;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import plugin.misc.IPlugin;
public class TestJarLoading {
public static void main(String[] args) {
IPlugin plugin = null;
while(true) {
try {
File file = new File("C:\\plugins\\test.jar");
String classToLoad = "jartest.TestPlugin";
URL jarUrl = new URL("jar", "","file:" + file.getAbsolutePath()+"!/");
URLClassLoader cl = new URLClassLoader(new URL[] {jarUrl}, TestJarLoading.class.getClassLoader());
Class loadedClass = cl.loadClass(classToLoad);
plugin = (IPlugin) loadedClass.newInstance();
plugin.doProc();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
IPlugin - это простой интерфейс только с одним методом doProc:
public interface IPlugin {
void doProc();
}
и jartest.TestPlugin - это реализация этого интерфейса, где doProc просто печатает некоторые утверждения.
Теперь я упакую класс jartest.TestPlugin в банку с именем test.jar и поместил его под C:\plugins и запустил этот код. Первая итерация выполняется плавно, и класс загружается без проблем.
Когда программа выполняет оператор sleep, я заменяю C:\plugins\test.jar новым банком, содержащим обновленную версию того же класса, и жду следующей итерации while. Теперь вот что я не понимаю. Иногда обновляемый класс перезагружается без проблем, то есть следующая итерация выполняется нормально. Но иногда я вижу исключение:
java.lang.NullPointerException
at java.io.FilterInputStream.close(FilterInputStream.java:155)
at sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream.close(JarURLConnection.java:90)
at sun.misc.Resource.getBytes(Resource.java:137)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:256)
at java.net.URLClassLoader.access$000(URLClassLoader.java:56)
at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
at test.misc.TestJarLoading.main(TestJarLoading.java:22)
Я искал в сети и почесал голову, но не могу прийти к какому-либо выводу, почему это исключение выбрано, и это тоже - только иногда, не всегда.
Мне нужен ваш опыт и знания, чтобы понять это. Что не так с этим кодом? Пожалуйста, помогите!
Сообщите мне, если вам нужна дополнительная информация. Спасибо, что посмотрели!