【问题标题】:Shared JNI library (.so) in Tomcat - UnsatisfiedLinkErrorTomcat 中的共享 JNI 库 (.so) - UnsatisfiedLinkError
【发布时间】:2017-02-23 22:13:58
【问题描述】:

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

我已经想不出我能做什么了。有任何想法吗?我在 SO 上尝试了大多数解决方案。 谢谢。

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

【问题讨论】:

    标签: java tomcat web-applications java-native-interface shared-libraries


    【解决方案1】:

    你有没有试过把共享的 JNI 库放在服务器的 lib 目录中。它应该被所有部署的 Web 应用程序共享。

    【讨论】:

    • 然后使用 System.loadLibrary 从那里加载它?还是把它放在那里,让 Tomcat 来处理这一切?
    • System.loadLibrary("libraryName");
    • 是的,我确实尝试过。同一件事情。最初它是由 ContextInitializer 从 .jar 文件中提取并放入 tomcat/bin 文件夹中的。
    • 您不仅需要将库放在“lib”中。您必须将加载它的代码放在那里,因此它由 tomcat 共享类加载器而不是由 webapp 类加载器加载(因为您已经发现您无法加载它两次并且另一个 webapp 无法访问它)
    • 假设我手动提取库并将其放在“lib”文件夹中。我是否必须从 myWebApp1 调用“System.loadLibrary”才能使用该库中的任何功能?或者Tomcat会在启动时默认加载它?因为我试图让 Tomcat 加载它但它不起作用:(
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      是的,当您尝试加载已经加载了我的另一个 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");
      

      一切顺利!

      【讨论】:

      • 而且.class文件DLLBootstrapper应该在tomcat lib文件夹中吧?
      • 或者我应该将.class文件打包在一个jar中并放入tomcat lib文件夹中?
      • 是的。你应该把它放在tomcat lib文件夹中。 Tomcat 会在启动时将其拾取
      • .class 还是应该将其导出为 jar?
      • 只需要 .class 就可以了
      【解决方案4】:

      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我的回答中查看更多详细信息和示例

      【讨论】:

        猜你喜欢
        • 2013-06-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-22
        • 1970-01-01
        • 2012-02-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多