我在Tomcat7中部署的两个Web应用程序之间共享了一个JNI库(.so)。我在部署的第一个Web应用程序中只使用System.loadLibrary加载一次库,然后在第二个我正在检查它是否已经加载到不再加载(我尝试在两者中加载它和我得到UnsatisfiedLinkError - 库由另一个类加载器加载)。我可以在第一个应用程序中对本机库进行任何调用,但在第二个应用程序中,我使用我要调用的方法名称获取UnsatisfiedLinkError。
我的想法已经用完了。有任何想法吗?我在SO上尝试了大部分解决方案。 谢谢。
修改 是的,我尝试在tomcat lib文件夹中添加库并从那里加载它。最初它位于bin文件夹中,同样的问题也出现了。
答案 0 :(得分:2)
是的,当您尝试加载已加载我的另一个Web应用程序的库时,会发生这种情况。 Tomcat为每个Web应用程序使用单独的类加载器,它不允许您通过另一个类加载器多次向JVM加载相同的本机库
移动任何共享jar文件(如果有的话)从您的sharedlib.so中消耗JNI。将系统路径添加到sharedlib,
export LD_LIBRARY_PATH=/path/to/whereyourlinklibrary
编写一个这样的简单类,使您可以在tomcat启动时加载共享库。只需编译该类并将其放在tomcat lib文件夹
中package msm;
public class DLLBootstrapper {
static {
System.loadLibrary("sharedlib");
}
public static void main(String args[]) {
System.out.println("Loaded");
}
}
您现在可以从任何Web应用程序(可能在启动侦听器中)加载此类
Class.forName("msm.DLLBootstrapper");
很高兴去!
答案 1 :(得分:0)
您是否尝试将共享JNI库放在server的lib目录中。它应该由所有部署的Web应用程序共享。
答案 2 :(得分:0)
您需要从服务器类加载器中加载任何本机代码,而不是webapp类加载器。我建议写一个previewFile(path [,displayname])
,它将共享对象的二进制映像加载到VM中。这只会发生一次。有关如何正确执行此操作,请参阅AprLifecycleListener
。它包括一个JNI组件,它可能完全代表你的情况。
共享对象必须驻留在Listener
和${catalina.home}/lib
帽子中才能指向它。
答案 3 :(得分:0)
Tomcat从版本9.0.13、8.5.35和7.0.92开始具有针对此问题的内置解决方案:
1)使用JniLifecycleListener加载本机库。
2)使用org.apache.tomcat.jni.Library中的loadLibrary()或load()代替System。
在java.lang.UnsatisfiedLinkError: Native Library XXX.so already loaded in another classloader的答案中查看更多详细信息和示例