У меня есть приложение, которое я разрабатываю и которое использует как jar-библиотеки, так и собственные системные библиотеки. Моя проблема в том, что загрузчик классов по умолчанию пытается загрузить статические классы задолго до вызова main. Поскольку путь к классам еще не содержит нативных библиотек, которые требуются статическим классам, java.lang.NoClassDefFoundError генерируется в первой оцененной статической ссылке.
Вот как выглядит мой недоступный метод загрузки библиотеки:
private static void load_libraries() {
try {
String osname = getOSName();
if (osname == null) {
throw new RuntimeException("The system you are running on is not supported");
}
URL u = NativeLibs.class.getResource(osname);
URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Class urlClass = URLClassLoader.class;
Method method = urlClass.getDeclaredMethod("addURL", new Class[]{URL.class});
method.setAccessible(true);
method.invoke(urlClassLoader, new Object[]{u});
} catch (IllegalAccessException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Failed to load native libs", ex);
} catch (IllegalArgumentException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Failed to load native libs", ex);
} catch (InvocationTargetException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Failed to load native libs", ex);
} catch (NoSuchMethodException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Failed to load native libs", ex);
} catch (SecurityException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, "Failed to load native libs", ex);
}
}
Итак, позвольте мне объяснить, что здесь происходит. Прежде всего getOSName () возвращает строку, представляющую семейство ОС, на котором я работаю. Возвращает ноль, если ОС не поддерживается. На случай, если у меня возникнут проблемы с этим методом, я также опубликую его:
private static String getOSName() {
String os = System.getProperty("os.name").toLowerCase(Locale.US);
if (os.indexOf("win") >= 0) {
return "windows";
} else if (os.indexOf("mac os x") >= 0) {
return "macosx";
} else if (os.indexOf("nux") >= 0) {
return "linux";
} else if (os.indexOf("solaris") >= 0) {
return "solaris";
} else {
return null;
}
}
Возвращаемые строки - это имена каталогов, которые метод load_libraries () использует для определения относительного URL-адреса, который я рефлексивно передаю загрузчику классов для загрузки библиотек. Моя проблема в том, что выполнение во время выполнения никогда не достигает load_libraries (), хотя это первый метод в main.
Одним из очевидных решений является статическая загрузка собственных библиотек с помощью пользовательских jar-файлов. Я не хочу статически связывать нативные библиотеки, если этого вообще можно избежать, потому что это противоречит цели переносимости платформы java. Другое решение, которое я уже вывел, - это исполняемый файл системы, который может запускать jar приложений с определенным автоматическим путем к классам из исполняемого файла системы, но, тем не менее, это решение требует нескольких исполняемых файлов, которые зависят от платформы.
Итак, вот мой вопрос:
Могу ли я заставить загрузчик классов запустить мой метод загрузки библиотеки, прежде чем он будет инициализировать статические объекты? Это потребует настроенного ClassLoader? Если для этого требуется пользовательский ClassLoader, решит ли проблема просто передача системного свойства, представляющего загрузчик классов по умолчанию?
Спасибо, надеюсь, я написал достаточно подробный вопрос!