【发布时间】:2011-03-27 16:08:40
【问题描述】:
我正在开发一个使用 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() 所做的就是返回一个代表我正在运行的操作系统系列的字符串。如果操作系统不受支持,则返回 null。以防万一我在该方法中遇到问题,我会继续发布它:
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,那么简单地传递代表默认类加载器的系统属性会解决问题吗?
谢谢,我希望我写了一个足够详细的问题!
【问题讨论】:
标签: java dynamic static default classloader