比如拿 jna 加载海康测速库文件为例:
windows环境: (HCNetSDK) Native.loadLibrary("E:\\xxx\\HCNetSDK.dll", HCNetSDK.class),
linux环境:(HCNetSDK) Native.loadLibrary("/xxx/libhcnetsdk.so", HCNetSDK.class)。
但是 Native.loadLibrary 的第一个参数是一个磁盘路径,但是我们习惯将各种库文件( .dll、.so ) 像源码一样存放到工程中的 src/main/resources 下面,否则 jar 部署到服务器后,还需要在服务器上建一个目录,再将库文件上传进去,特别麻烦,如果就想将库文件存在到源码中的 src/main/resources 下面,如下:
将打包后的 jar上传到服务器,java -jar 执行,Native.loadLibrary就可以加载呢?
思路是工程启动后在 Native.loadLibrary 之前,将 jar 中 "BOOT-INF/classes/window_dll" 或者 "BOOT-INF/classes/linux_os" 中的 dll 或 os 库文件解压到外部磁盘目录中。
要注意需要修改 pom.xml 中 build.resources.resource.filtering 策略,之前可能是这样的:
需要修改成如下的:
然后在 Native.loadLibrary 之前添加如下代码:
// 解压 jar 中 BOOT-INF/classes/windows_dll 或者 BOOT-INF/classes/linux_os 中的 库文件到 配置路径 ${hk_car_speed_check.jna_lib_path} 中
String targetFolderInJar = "BOOT-INF/classes/";
if (OsUtils.isWindows()){
targetFolderInJar += "windows_dll";
}else if (OsUtils.isLinux()){
targetFolderInJar += "linux_os";
}
// String destDir = "E:/xxx/dll/windows_test1";
String destDir = jnaLibPath;
File file = new File(destDir);
file.mkdirs();
JarUtils.extractFilesFromJar(targetFolderInJar, destDir );
JarUtils源码:
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.FileCopyUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@Slf4j
public class JarUtils {
public static void extractFilesFromJar(String targetFolderInJar, String destDir) {
String jarFile = System.getProperty("java.class.path");
if (StringUtils.isBlank(jarFile) || !jarFile.endsWith(".jar")) {
log.error("定位jar失败");
return;
}
try (JarFile jar = new JarFile(jarFile)) {
Enumeration enumeration = jar.entries();
while (enumeration.hasMoreElements()) {
JarEntry jarEntry = (JarEntry) enumeration.nextElement();
// BOOT-INF/classes/linux_so/libssl.so
// BOOT-INF/classes/windows_dll/HCNetSDKCom/AudioRender.dll
String name = jarEntry.getName();
// 根据路径定位目标文件
if (!name.startsWith( targetFolderInJar )) {
continue;
}
// 优化路径名称,这里也可以直接用jarEntry.getName()来看下效果
// "/HCNetSDKCom/AudioRender.dll"
String fixedName = jarEntry.getName().replace(targetFolderInJar, "");
// "E:/git/xxx/dll/windows_test1/HCNetSDKCom/AudioRender.dll"
// String destPath = destDir + File.separator + fixedName;
String destPath = destDir + fixedName;
System.out.println( "destPath = " + destPath );
File file = new File( destPath );
if( jarEntry.isDirectory() ) {
// 是目录
file.mkdirs();
}else {
// 是文件
// try (InputStream is = jar.getInputStream(jarEntry);
try (InputStream is = jar.getInputStream( jar.getEntry(name) );
FileOutputStream fos = new FileOutputStream(file)) {
FileCopyUtils.copy( is,fos );
}
}
}
} catch (IOException e) {
log.error("提取文件异常", e);
}
}
}