java - 从类路径加载 native 库

标签 java java-native-interface java.library.path

我有一个遵循 Standard Directory Layout 的项目设置(虽然没有使用 Maven):

src/main
      | java
      | resources
         | library.dll

native DLL 位于 resources 文件夹中,sources 位于 java 文件夹中。资源文件夹是 Java 类路径的成员。

我现在想加载一个 DLL,而不必设置 JRE -Djava.library.path 选项或设置 PATH 变量,这样生成的 jar 文件就可以只需双击即可开始。

是否可以在运行jar文件时无需额外配置,将资源文件夹添加到库搜索路径? 例如。使用类似于 list 中的 Class-Path 的设置?

最佳答案

我在 JNativeHook 中做过类似的事情,您将需要一些帮助程序代码来确定要为其加载代码的正确架构和操作系统(参见 NativeSystem 类)

// The following code covered under the GNU Lesser General Public License v3.
static {
    String libName = System.getProperty("jnativehook.lib.name", "JNativeHook");

    try {
        // Try to load the native library assuming the java.library.path was
        // set correctly at launch.
        System.loadLibrary(libName);
    }
    catch (UnsatisfiedLinkError linkError) {
        // Get the package name for the GlobalScreen.
        String basePackage = GlobalScreen.class.getPackage().getName().replace('.', '/');

        // Compile the resource path for the native lib.
        StringBuilder libResourcePath = new StringBuilder("/");
        libResourcePath.append(basePackage).append("/lib/");
        libResourcePath.append(NativeSystem.getFamily()).append('/');
        libResourcePath.append(NativeSystem.getArchitecture()).append('/');


        // Get what the system "thinks" the library name should be.
        String libNativeName = System.mapLibraryName(libName);
        // Hack for OS X JRE 1.6 and earlier.
        libNativeName = libNativeName.replaceAll("\\.jnilib$", "\\.dylib");

        // Slice up the library name.
        int i = libNativeName.lastIndexOf('.');
        String libNativePrefix = libNativeName.substring(0, i) + '-';
        String libNativeSuffix = libNativeName.substring(i);
        String libNativeVersion = null;

        // This may return null in some circumstances.
        InputStream libInputStream = GlobalScreen.class.getResourceAsStream(libResourcePath.toString().toLowerCase(Locale.English) + libNativeName);
        if (libInputStream != null) {
            try {
                // Try and load the Jar manifest as a resource stream.
                URL jarFile = GlobalScreen.class.getProtectionDomain().getCodeSource().getLocation();
                JarInputStream jarInputStream = new JarInputStream(jarFile.openStream());

                // Try and extract a version string from the Manifest.
                Manifest manifest = jarInputStream.getManifest();
                if (manifest != null) {
                    Attributes attributes = manifest.getAttributes(basePackage);

                    if (attributes != null) {
                        String version = attributes.getValue("Specification-Version");
                        String revision = attributes.getValue("Implementation-Version");

                        libNativeVersion = version + '.' + revision;
                    }
                    else {
                        Logger.getLogger(GlobalScreen.class.getPackage().getName()).warning("Invalid library manifest!\n");
                    }
                }
                else {
                    Logger.getLogger(GlobalScreen.class.getPackage().getName()).warning("Cannot find library manifest!\n");
                }
            }
            catch (IOException e) {
                Logger.getLogger(GlobalScreen.class.getPackage().getName()).severe(e.getMessage());
            }


            try {
                // The temp file for this instance of the library.
                File libFile;

                // If we were unable to extract a library version from the manifest.
                if (libNativeVersion != null) {
                    libFile = new File(System.getProperty("java.io.tmpdir"), libNativePrefix + libNativeVersion + libNativeSuffix);
                }
                else {
                    libFile = File.createTempFile(libNativePrefix, libNativeSuffix);
                }

                byte[] buffer = new byte[4 * 1024];
                int size;

                // Check and see if a copy of the native lib already exists.
                FileOutputStream libOutputStream = new FileOutputStream(libFile);

                // Setup a digest...
                MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
                DigestInputStream digestInputStream = new DigestInputStream(libInputStream, sha1);

                // Read from the digest stream and write to the file steam.
                while ((size = digestInputStream.read(buffer)) != -1) {
                    libOutputStream.write(buffer, 0, size);
                }

                // Close all the streams.
                digestInputStream.close();
                libInputStream.close();
                libOutputStream.close();

                // Convert the digest from byte[] to hex string.
                String sha1Sum = new BigInteger(1, sha1.digest()).toString(16).toUpperCase();
                if (libNativeVersion == null) {
                    // Use the sha1 sum as a version finger print.
                    libNativeVersion = sha1Sum;

                    // Better late than never.
                    File newFile = new File(System.getProperty("java.io.tmpdir"), libNativePrefix + libNativeVersion + libNativeSuffix);
                    if (libFile.renameTo(newFile)) {
                        libFile = newFile;
                    }
                }

                // Set the library version property.
                System.setProperty("jnativehook.lib.version", libNativeVersion);

                // Load the native library.
                System.load(libFile.getPath());

                Logger.getLogger(GlobalScreen.class.getPackage().getName())
                        .info("Library extracted successfully: " + libFile.getPath() + " (0x" + sha1Sum + ").\n");
            }
            catch (IOException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
            catch (NoSuchAlgorithmException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
        else {
            Logger.getLogger(GlobalScreen.class.getPackage().getName())
                    .severe("Unable to extract the native library " + libResourcePath.toString().toLowerCase(Locale.English) + libNativeName + "!\n");

            throw new UnsatisfiedLinkError();
        }
    }
}

关于java - 从类路径加载 native 库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23189776/

相关文章:

java - Mac OS X 上的 JNotify?

java - 如何在 Spring Security 中将未找到 header 异常重定向到登录页面

java - 为什么我在 springboot 中收到错误 Factory method 'halLinkDisocoverer' throwed exception?

java - Spring web mvc 示例,引导,创建名称为 'jacksonObjectMapperBuilder' 的 bean 时出错

android - ndk-build 和 make APP for android 有什么区别?

java - 从 Eclipse 中的 build.xml 文件导入库

java - 使用 datastax java 驱动程序连接到本地 cassandra 节点?

java - 如何在hadoop map reduce中设置使用JNI创建的库文件的路径

java loadlibrary和native方法声明

java - liblpsolve55.so : cannot open shared object file: No such file or directory