是什么?
一、了解JNA之前,我们先了解一下JNA的前身JNI(Java Native Interface):通过使用 Java本地接口书写程序,可以确保代码在不同的平台上方便移植。 [1]
图解:
注意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来说简化了很多。
图解:
实践
三、举例:
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)目录结构:
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)测试效果
四、总结: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
说明
以上知识是本人参考其他网址并自我实践总结出遇到的问题,大部分来自原文内容,再加上少部分自己遇到的问题。
在此向原文作者表示感谢。
以上内容如有任何问题,请指正。