Приветствую!
Сегодня хочется поговорить о вопросе загрузки jar, находящегося внутри другого jar. При этом, мы предполагаем, что этот "большой" jar-файл был статически прилинкован к приложению и уже загружен.
К сожалению совсем легко это не сделать, но и усилий надо приложить совсем немного.
Единственный возможный выход - это сохранить эти файлы на файловой системе (лучше всего во временной папке) и передать URLClassLoader-у пути к файлам.
В этой части мы рассмотрим вариант, когда мы точно знаем как называются и где находятся те jar-ки, которые мы хотим загрузить из большого. В следующей части поговорим о варианте, когда нам нужно загрузить все jar-файлы, которые найдутся в главном.
Итак, приступим. Наша задача достаточно проста:
Сегодня хочется поговорить о вопросе загрузки jar, находящегося внутри другого jar. При этом, мы предполагаем, что этот "большой" jar-файл был статически прилинкован к приложению и уже загружен.
К сожалению совсем легко это не сделать, но и усилий надо приложить совсем немного.
Единственный возможный выход - это сохранить эти файлы на файловой системе (лучше всего во временной папке) и передать URLClassLoader-у пути к файлам.
В этой части мы рассмотрим вариант, когда мы точно знаем как называются и где находятся те jar-ки, которые мы хотим загрузить из большого. В следующей части поговорим о варианте, когда нам нужно загрузить все jar-файлы, которые найдутся в главном.
Итак, приступим. Наша задача достаточно проста:
- Находим внутренний jar через вызов getResource текущего ClassLoader
- Получаем у него InputStream
- Создаем временный файл
- Заливаем наш jar-ник во временный файл
- Закрываем все потоки
- URL временного файла скармливаем URLClassLoader
- Здесь на выбор - либо через ClassLoader вызываем loadClass, либо через Class.forName - загружаем нужный класс
- Повторяем все шаги для остальных jar-ков
А вот и код
private URL getInsideJarURL(ClassLoader cl, String resourceName) throws IOException {
debug("Get inside JAR URL for resource {}", resourceName);
try {
URL resourceUrl = cl.getResource(resourceName);
InputStream is = resourceUrl.openStream();
File tempFile = File.createTempFile(resourceName, ".jar");
tempFile.deleteOnExit();
FileOutputStream fos = new FileOutputStream(tempFile);
byte[] buf = new byte[1024];
int len;
while (0 < (len = is.read(buf, 0, 1024))) {
fos.write(buf, 0, len);
}
is.close();
fos.close();
info("Saved inside JAR resource {} as {}", resourceName, tempFile.getAbsolutePath());
return tempFile.toURI().toURL();
} catch (IOException e) {
error("Error loading resource jar {}", resourceName);
throw e;
}
}
и его использование:
ClassLoader cl = getClass().getClassLoader();
classLoader = new URLClassLoader(new URL[] { getInsideJarURL(cl, "jar-1.jar"),
getInsideJarURL(cl, "jar-2.jar"), getInsideJarURL(cl, "jar-3.jar") }, cl);
Class<?> myClass = Class.forName("MyClass", true, classLoader);
Если есть желание подгрузить сразу все классы - это тоже не проблема.
Мы знаем наш файл, можем создать JarFile и пробежаться по его JarEntry.
Если мы хотим "скормить" URLClassLoader не всю нашу библиотеку, а лишь отдельные классы, то здесь тоже нет проблемы. Мы выгружаем библиотеку как и раньше, а вот дальше мы создаем объект JarFile на основе нашего файла и достаем те JarEntry, которые нам нужны и тоже сохраняем их в файлы. А затем отдаем URLClassLoader ссылки на выгруженные файлы классов.
Если мы хотим "скормить" URLClassLoader не всю нашу библиотеку, а лишь отдельные классы, то здесь тоже нет проблемы. Мы выгружаем библиотеку как и раньше, а вот дальше мы создаем объект JarFile на основе нашего файла и достаем те JarEntry, которые нам нужны и тоже сохраняем их в файлы. А затем отдаем URLClassLoader ссылки на выгруженные файлы классов.
Комментариев нет:
Отправить комментарий