重新部署为Web应用程序时,Java JNI GDAL本机库错误与ClassLoader

时间:2017-08-02 14:04:04

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

我使用的是GDAL本机库(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以应用程序启动时,这很有效,但是,如果我重新部署应用程序,它将返回错误:
    引起:java.lang.UnsatisfiedLinkError:本机库/usr/lib/java/gdal/libgdaljni.so已经加载到另一个类加载器中

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

1 个答案:

答案 0 :(得分:0)

为了避免将库添加到Tomcat / lib文件夹,我将所有GDAL本机文件夹复制到带有时间戳的临时目录(例如:/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应用程序时,Classloader将从另一个文件夹加载库,而不会出现错误,并且usrPathsField只包含一个指向/ tmp / gdal_native / timestamp的文件夹路径。