是什么?

一、了解JNA之前,我们先了解一下JNA的前身JNI(Java Native Interface):通过使用 Java本地接口书写程序,可以确保代码在不同的平台上方便移植。 [1]

图解:

java 第三方 调用demo java调用第三方库_java 第三方 调用demo

注意jni的编写命名是有要求的,这里可以参考:https://baike.baidu.com/item/JNI/9412164?fr=aladdin#书写步骤

二、JNA(Java Native Access):提供一组Java工具类用于在运行期间动态访问系统本地库(native library:如Window的dll)而不需要编写任何Native/JNI代码。开发人员只要在一个java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射。

简而言之,就是jna基于jni的方式封装了很多api,在使用上面相对于jni来说简化了很多。

图解:

java 第三方 调用demo java调用第三方库_JNA_02

实践

三、举例:

1)编写c源码(sum.cpp)

extern "C" {
    int sum(int x, int y) {
        return x + y;
    }
}

2)装换成*.dll/*.so文件

windows
gcc -m64 -shared -o <dll_name> <c_name>

linux
gcc -m64 -fPIC -shared -o <so_name> <c_name>

注意: windows环境中,使用windows的c环境导包,名称可以随便取,用dll的文件格式。linux中使用linux的c环境打包,以lib(name).so的方式命名。

windows版本要在windows下编译,linux版本在linux下编译。

注意这里要说明一下,windows下的gcc是使用MinGW编译的,而且最好是64位的,否则可能使用的springboot64位加载失败。

具体如何安装MinGW,这里有如下链接:

MinGW32:点我 (防止网页失效,可直接去这里下载)

MinGW64:点我(防止网页失效,可直接去这里下载)

32位的需要下载之后对编译器进行配置,64位不需要配置。

测试是否可以使用gcc

cmd ==> 输入命令:gcc -v

3)目录结构:

java 第三方 调用demo java调用第三方库_java_03

4)maven依赖(pom.xml)

<dependency>
     <groupId>com.sun.jna</groupId>
     <artifactId>jna</artifactId>
     <version>3.0.9</version>
</dependency>

5)实现过程

package com.cetc.util;

import com.sun.jna.Library;
import com.sun.jna.Native;

import java.io.File;

public class SumUtil {

    public interface Sum extends Library {

        //动态库接口
        int sum(int x, int y);
        
        //创建动态库实例
        Sum INSTANCE = (Sum) Native.loadLibrary("sum", Sum.class);
    }

    //加载库的绝对路径,这里是windows测试使用的,如果在linux下运行,注释下面static中代码
    static {
        File file = new File("src/main/resources/lib/sum.dll");
        System.load(file.getAbsolutePath());
    }

    //测试
    public static void main(String[] args) {
        System.out.println("***************************");
        System.out.println(Sum.INSTANCE.sum(1,2));
        System.out.println("***************************");
    }
}

6)测试效果

java 第三方 调用demo java调用第三方库_java 第三方 调用demo_04

四、总结:JNA在很大程度上面简化了不同语言之间的连接,通过动态库的方式,来提供给Java调用。使用场景一般用于性能要求比较高的场景,比如opencv等。

注意:在实际开发工程中,不能直接把dll/so文件打入jar,因为System.load,加载的是绝对路径,可以放入Java的include.或者使用assembly的打包方式等。

关于linux下libxxx.so动态库位置

建议放到/lib64目录下,执行命令ldconfig重新加载动态库即可。

下面说明一下:

Java加载dll或so库文件的路径 java.library.path

1. Java的System.load 和 System.loadLibrary都可以用来加载库文件
2.例如你可以这样载入一个windows平台下JNI库文件:
System.load("C://Documents and Settings//TestJNI.dll"); 绝对路径
3. System.loadLibrary参数为库文件名
例如你可以这样载入一个windows平台下JNI库文件
System.loadLibrary ("TestJNI");
这里TestJNI必须在 java.library.path这一jvm变量所指向的路径中,可以通过如下方法获得该变量的值:
  System.getProperty("java.library.path");
默认情况下,Windows平台下包含下面的路径:
  1)和jre相关的目录
  2)程序当前目录
  3)Windows目录
  4)系统目录(system32)
  5)系统环境变量path指定的目录

4.在linux下添加一个java.library.path的方法如下:
  在/etc/profile 后面加上一行 export LB_LIBRARY_PATH=路径

5.在执行程序的时候可以显示指定, -Djava.library.path=路径,这种会清除掉预设置的java.library.path的值 。实例如下:
java -jar -Djava.library.path=/home/fly/Desktop/sound_dream  sound.war
 

说明

以上知识是本人参考其他网址并自我实践总结出遇到的问题,大部分来自原文内容,再加上少部分自己遇到的问题。

在此向原文作者表示感谢。

以上内容如有任何问题,请指正。