Tomcat 中的共享 JNI 库 (.so) - UnsatisfiedLinkError

Shared JNI library (.so) in Tomcat - UnsatisfiedLinkError

我有一个在 Tomcat7 中部署的两个 Web 应用程序之间共享的 JNI 库 (.so)。我在第一个正在部署的 Web 应用程序中仅使用 System.loadLibrary 加载库一次,然后在第二个中我检查它是否已经加载以不再加载(我尝试在两者中加载它并且我得到 UnsatisfiedLinkError - 库被另一个类加载器加载)。我可以在第一个应用程序中对本机库进行任何调用,但在第二个应用程序中,我得到 UnsatisfiedLinkError 以及我尝试调用的方法名称。

我运行不知道自己能做什么。有任何想法吗?我在 SO 上尝试了大部分解决方案。 谢谢。

编辑 是的,我尝试在 tomcat lib 文件夹中添加库并从那里加载它。最初它在 bin 文件夹中,但出现了同样的问题。

您是否尝试过将共享 JNI 库放在 server.It 的 lib 目录中应该由所有部署的 Web 应用程序共享。

您需要从服务器类加载器而不是 webapp 类加载器中加载任何本机代码。我建议编写一个 Listener 将共享对象的二进制映像加载到 VM 中。这只会发生一次。请参阅 AprLifecycleListener 以了解如何正确执行此操作。它包括一个 JNI 组件,它可能完全代表您的情况。

共享对象必须驻留在 ${catalina.home}/libLD_LIBRARY_PATH 帽子中才能指向它。

是的,当您尝试加载已加载我的另一个 Web 应用程序的库时,会发生这种情况。 Tomcat,为每个 Web 应用程序使用单独的 class 加载器,它不允许您通过另一个 class 加载器

将同一个本地库多次加载到 JVM

移动任何共享 jar 文件,如果有任何消耗您的 JNI sharedlib.so。将系统路径添加到 sharedlib ,

export LD_LIBRARY_PATH=/path/to/whereyourlinklibrary

像这样写一个简单的 class,这样您就可以在 tomcat 启动时加载您的共享库。只需编译此 class 并将其放入 tomcat lib 文件夹

package msm;
public class DLLBootstrapper {

     static {
      System.loadLibrary("sharedlib");
     }

     public static void main(String args[]) {
      System.out.println("Loaded");
     }

    }

您现在可以从您的任何 Web 应用程序(可能在启动侦听器中)加载此 class

Class.forName("msm.DLLBootstrapper");

干得好!

Tomcat 从版本 9.0.13、8.5.35 和 7.0.92 开始有针对此问题的内置解决方案:

1) 使用 JniLifecycleListener 加载原生库。

2) 使用 org.apache.tomcat.jni.Library 中的 loadLibrary() 或 load() 而不是 System.

的回答中查看更多详细信息和示例