JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架。非常强大、易用,功能上类似与.NET的P/Invoke。
我们知道,使用JNI调用.dll/.so共享类库是非常非常麻烦和痛苦的。例如:有一个现有的.dll/.so文件,如果使用JNI技术调用:
经过2个繁琐的步骤才能在Java中调用本地代码。因此,很少有Java程序员愿意编写调用dll/.so库中的原生函数的java程序。这也使Java语言在客户端上乏善可陈。可以说JNI是Java的一大弱点!
而在.NET平台上,强大的P/Invoke技术使我们Java程序员非常羡慕。使用P/Invoke技术,只需要使用编写一个.NET函数,再加上一个声明的标注,就可以直接调用dll中的函数。不需要你再使用C语言编写dll来适配。
现在,不需要再羡慕.NET的P/Invoke机制了。JNA把对dll/.so共享库的调用减少到了和P/Invoke相同的程度。使用JNA,不需要再编写适配用的.dll/.so,只需要在Java中编写一个接口和一些代码,作为.dll/.so的代理,就可以在Java程序中调用dll/so。
当然,凡事都具有两面性。JNA是建立在JNI技术基础之上的一个Java类库,原来使用JNI,你必须手工用C写一个动态链接库,在C语言中映射Java的数据类型。JNA中,它提供了一个动态的C语言编写的转发器,可以自动实现Java和C的数据类型映射。你不再需要编写C动态链接库。当然,这也意味着,使用JNA技术比使用JNI技术调用动态链接库会有些微的性能损失。可能速度会降低几倍。但影响不大。
示例一:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
public class JNATest {
//继承Library,用于加载库文件
public interface Clibrary extends Library{
Clibrary INSTANCE = (Clibrary) Native.loadLibrary(
(Platform.isWindows() ? "msvcrt" : "c"), Clibrary.class);
/*
* 声明一个跟C语言的printf()一样的方法,参数类型要匹配
* C语言的printf()方法原型如下:
* int __cdecl printf(const char * __restrict__ _Format,...);
*/
void printf(String format, Object... args);
}
public static void main(String...strings) {
//调用
Clibrary.INSTANCE.printf("Hello, World->%d",2019);
}
}
输出:Hello, World->2019
示例二:
1)java代码:JNATest.java
pom.xml
com.sun.jna
jna
3.0.9
import com.sun.jna.Library;
import com.sun.jna.Native;
public class JNATest {
//继承Library,用于加载库文件
public interface Clibrary extends Library{
//加载libhello.so链接库
Clibrary INSTANTCE1 = (Clibrary) Native.loadLibrary("hello", Clibrary.class);
//此方法为链接库中的方法
void test();
}
public static void main(String...strings) {
//调用
Clibrary.INSTANTCE1.test();
}
}
2)C代码:
#头文件
$ vim hello.h
void test();
#c文件
$ vim hello.c
#include
#include "hello.h"
void test() {
printf("hello jna...");
}
3)编译C成动态链接库:
#先编译验证是否有错误
$ pwd
/data/kevinliu/jna
$ gcc -c hello.c
$ ll
-rw-r--r-- 1 root root 81 Oct 12 14:41 hello.c
-rw-r--r-- 1 root root 13 Oct 12 14:40 hello.h
-rw-r--r-- 1 root root 1472 Oct 12 14:41 hello.o
$ rm -rf hello.o
#动态连接
$ gcc -fPIC -shared -o libhello.so hello.c
$ ll
-rw-r--r-- 1 root root 81 Oct 12 14:41 hello.c
-rw-r--r-- 1 root root 13 Oct 12 14:40 hello.h
-rwxr-xr-x 1 root root 7868 Oct 12 14:41 libhello.so
4)打包java代码、运行:
#mvn打包
$ mvn package
$ java -jar Test.jar
Java HotSpot(TM) 64-Bit Server VM warning: You have loaded library /tmp/jna2509150676913835975.tmp which might have disabled stack guard. The VM will try to fix the stack guard now.
It's highly recommended that you fix the library with 'execstack -c ', or link it with '-z noexecstack'.
Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'hello': libhello.so: cannot open shared object file: No such file or directory
at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:145)
at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:188)
at com.sun.jna.Library$Handler.(Library.java:123)
at com.sun.jna.Native.loadLibrary(Native.java:255)
at com.sun.jna.Native.loadLibrary(Native.java:241)
at JNATest$Clibrary.(JNATest.java:8)
at JNATest.main(JNATest.java:16)
报错是因为JVM没法找到动态链接库的路径,此时需要把动态链接库加入系统的/lib目录或修改环境变量等。
$ pwd
/data/kevinliu/jna
$ ll
drwxr-xr-x 2 root root 4096 Oct 12 14:42 conf
-rw-r--r-- 1 root root 81 Oct 12 14:41 hello.c
-rw-r--r-- 1 root root 13 Oct 12 14:40 hello.h
drwxr-xr-x 2 root root 4096 Oct 12 14:42 lib
-rwxr-xr-x 1 root root 7868 Oct 12 14:41 libhello.so
-rw-r--r-- 1 root root 24395 Oct 12 14:42 Test.jar
$ pwd >> /etc/ld.so.conf
$ ldconfig
$ java -jar Test.jar
Java HotSpot(TM) 64-Bit Server VM warning: You have loaded library /tmp/jna3716912741417413426.tmp which might have disabled stack guard. The VM will try to fix the stack guard now.
It's highly recommended that you fix the library with 'execstack -c ', or link it with '-z noexecstack'.
hello jna...
参考:https://www.iteye.com/blog/liuzhijun-1744630
示例三:调用C++
1)java代码:
同上
2)C++代码
hello.cpp
#include
#include
using namespace std;
void test() {
cout<<"hello jna..."<
3)编译C++生成动态连接库
#编译验证是否有错
$ g++ -c hello.cpp
$ g++ -fPIC -shared -o libhello.so hello.cpp
4)调用:
$ java -jar Test.jar
Java HotSpot(TM) 64-Bit Server VM warning: You have loaded library /tmp/jna7304511378175985020.tmp which might have disabled stack guard. The VM will try to fix the stack guard now.
It's highly recommended that you fix the library with 'execstack -c ', or link it with '-z noexecstack'.
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up function 'test': /data/kevinliu/jna/libhello.so: undefined symbol: test
at com.sun.jna.Function.(Function.java:129)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:250)
at com.sun.jna.Library$Handler.invoke(Library.java:191)
at com.sun.proxy.$Proxy0.test(Unknown Source)
at JNATest.main(JNATest.java:16)
原因是,C++中,方法必须加上extern “C”,否则无法找到c++方法。
#include
using namespace std;
extern "C"
{
void test() {
cout<<"hello jna..."<
再次编译、生成动态连接文件,然后运行即可。