重新部署为 Web 应用程序时,ClassLoader 出现 Java JNI GDAL native 库错误

标签 java c++ tomcat java-native-interface gdal

我正在使用 GDAL native 库(C++,它安装在/usr/lib/java/gdal 中)。我不久前发现了一个技巧,让 Tomcat 可以加载 Web 应用程序和这个库(不能使用 System.load() 或 System.loadLibrary(),因为它们都会返回错误)

Caused by: java.lang.UnsatisfiedLinkError: org.gdal.osr.osrJNI.new_SpatialReference__SWIG_1()J

然后我需要使用一个技巧在应用程序启动时将库路径添加到 JVM:

    final Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths");
    usrPathsField.setAccessible(true);

    // get array of paths
    final String[] paths = (String[]) usrPathsField.get(null);

    // check if the path to add is already present
    for (String path : paths) {
        if (path.equals(pathToAdd)) {
            return;
        }
    }

    //add the new path
    final String[] newPaths = Arrays.copyOf(paths, paths.length + 1);
    newPaths[newPaths.length - 1] = pathToAdd;
    usrPathsField.set(null, newPaths);

这在 Tomcat 启动应用程序时运行良好,但是,如果我重新部署应用程序,它将返回错误:
Caused by: java.lang.UnsatisfiedLinkError: Native Library/usr/lib/java/gdal/libgdaljni.so already loaded in another classloader

我在 StackOverflow 中找不到任何解决方案,所以我在这里询问是否有人可以提供一些信息。我也不能更改或添加库路径到环境变量或 Tomcat 文件夹,所有这些都应该只在 Java 代码中完成。

最佳答案

因此,为了避免将库添加到 Tomcat/lib 文件夹,我将所有 GDAL native 文件夹复制到带有时间戳的临时目录(例如:/tmp/gdal_native/date.time),然后我正常使用上面的代码,除非它检查以前的路径,否则它将用新路径覆盖。

String tmpTargetNativeFolderPath = "/tmp/gdal_native" + "/" + current date time
int i = 0;
// check if the path to add is already present
for (String path : paths) {
    String pathFolder = StringUtils.substringBeforeLast(path, "/");
    if (pathFolder.equals("/tmp/gdal_native")) {
        // Override the old path with the new one
        paths[i] = tmpTargetNativeFolderPath;
        usrPathsField.set(null, paths);
        return;
    }
    i++;
}

然后,当重新部署 Web 应用程序且没有错误且 usrPathsField 仅包含一个文件夹路径到/tmp/gdal_native/timestamp 时,Classloader 将从另一个文件夹加载库。

关于重新部署为 Web 应用程序时,ClassLoader 出现 Java JNI GDAL native 库错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45463133/

相关文章:

java - 要求用户选择一个联系人,然后能够在以后查找该联系人的信息?

java - 为 Vuforia 创建网格 (Java)

java - Eclipse - 无法从 'https://services.gradle.org/distributions/gradle-2.1-bin.zip' 安装 Gradle 发行版

c++ - 将 50 位二进制值转换为整数

c++ - VS 2015 宏解释

java - java中如何比较两个列表对象?

c++ - 将 Matlab 转换为 C++

linux - centos7.2上tomcat无法用systemctl启动

maven - 从 .war 文件中排除文件夹

java - 使用 maven 将 war 部署到远程 Tomcat 8 时出现 401(未经授权)错误