JNA简单示例

JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架。非常强大、易用,功能上类似与.NET的P/Invoke。
我们知道,使用JNI调用.dll/.so共享类库是非常非常麻烦和痛苦的。例如:有一个现有的.dll/.so文件,如果使用JNI技术调用:

  • 首先要另外用c/c++写一个.dll/.so共享库,使用SUN规定的数据结构替代C语言的数据结构,调用已有的dll/so中公布的函数;
  • 然后再在Java中载入这个适配器dll/so,再编写Java   native函数作为dll中函数的代理。

JNI教程:JNI 简单示例_jni实例_赶路人儿的博客-CSDN博客

经过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
<dependency>
	<groupId>com.sun.jna</groupId>
	<artifactId>jna</artifactId>
	<version>3.0.9</version>
</dependency>


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 <stdio.h>
#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 <libfile>', 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.<init>(Library.java:123)
	at com.sun.jna.Native.loadLibrary(Native.java:255)
	at com.sun.jna.Native.loadLibrary(Native.java:241)
	at JNATest$Clibrary.<clinit>(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 <libfile>', or link it with '-z noexecstack'.
hello jna...

参考:JNA入门实例 - 我的成长之路 http://foofish.net - ITeye博客

示例三:调用C++

1)java代码:

同上

2)C++代码

hello.cpp

#include <stdlib.h>
#include <iostream>
using namespace std;

void test() {
  cout<<"hello jna..."<<endl;
}

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 <libfile>', 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.<init>(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 <iostream>
using namespace std;

extern "C"
{
  void test() {
    cout<<"hello jna..."<<endl;
  }
}

再次编译、生成动态连接文件,然后运行即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赶路人儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值