java 中 Native.loadLibrary 不能加载 jar 包中库文件的解决方案

比如拿 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 下面,如下:

java 中 Native.loadLibrary 不能加载 jar 包中库文件的解决方案_第1张图片

将打包后的 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 策略,之前可能是这样的:

java 中 Native.loadLibrary 不能加载 jar 包中库文件的解决方案_第2张图片

需要修改成如下的:

java 中 Native.loadLibrary 不能加载 jar 包中库文件的解决方案_第3张图片

 然后在 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);
        }
    }
}

你可能感兴趣的:(java8,maven,springBoot,java,jar,maven,jna,springboot)