Java JNI GDAL 本机库在重新部署为 Web 应用程序时出现类加载器错误

Java JNI GDAL native library error with ClassLoader when redeploying as web application

本文关键字:应用程序 Web 错误 类加载 部署 本机 GDAL JNI 新部署 Java      更新时间:2023-10-16

我正在使用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:Native Library/usr/lib/java/gdal/libgdaljni.so 已经加载到另一个类加载器中

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

为了避免将库添加到 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 应用程序时,类加载器将从另一个文件夹加载库而没有错误,并且 usrPathsField 仅包含一个指向/tmp/gdal_native/timestamp 的文件夹路径。