我正在使用最近发布的Glassfish v3,在使用本地库时,glassfish会间歇性地抱怨
glassfish SEVERE: java.lang.UnsatisfiedLinkError: Native Library already loaded in another classloader
在之前的glassfish发行版(v2.2)中加载本机库的过程就是将.dll文件放在GLASSFISH_HOME \ lib中。现在我不知道v3中是否有这样一个神奇的文件夹,如果有的话。我还检查了管理界面,我认为有两个与我的问题有关的变量:Native Library Path Prefix和Native Library Path Suffix。我一直在网上搜索,找到他们做什么以及如何使用它们的充分描述,但显然没有人喜欢谈论它们。
答案 0 :(得分:4)
java.lang.UnsatisfiedLinkError: Native Library already loaded in another classloader
本机lib只能在JVM中加载一次,并且每当您在重新部署时加载新版本的调用类(System.loadLibrary(String)
调用所在的类)时,您将收到该错误消息。更多内容如下。
在之前的glassfish版本(v2.2)中加载本机库的过程就是将.dll文件放在
GLASSFISH_HOME\lib
中。
嗯,这实际上只是故事的第一部分。要加载本机库,您当然要将它放在库路径和上以从Java代码加载它。为此,惯例是包括一个静态初始化器,如下所示:
class FooWrapper {
static {
System.loadLibrary("foo");
}
native void doFoo();
}
}
假设您正在使用Web应用程序,最佳做法是不要将本机库或其JNI接口放在WEB-INF/lib
或WEB-INF/classes
下,以避免在重新加载应用程序时出现问题,如上所述。换句话说,调用System.loadLibrary(String)
的类应该由不受重新加载Web应用程序本身影响的类加载器加载。
所以我的问题是:你把代码放在哪里了?
PS:另一种选择是在加载之前检查dll是否已经可用但我不会这样做。
答案 1 :(得分:3)
首先:给定的本地类只能加载到一个类加载器中。
第二件事:servlet容器中的每个Web应用程序都有自己的类加载器。
第三件事:您必须非常小心地编写本机代码以允许其类被垃圾收集。
结果:将本机代码加载到Web应用程序后,如果您尝试卸载并重新加载,可能会出现这些错误。
在某种程度上,我跳过了这个主题的非常简单的变体:只需加载两个不同的webapps和相同的本地类。
有些人更喜欢在系统类加载器中加载本机代码,以避免出现此问题。