java调用go动态库

JNI 和 JNA

jni

JNI(Java Native Interface),如果使用JNI技 术调用,我们首先需要使用C语言另外写一个.dll/.so共享库,使用SUN规定的数据结构替代C语言的数据结构,调用已有的 dll/so中公布的函 数。然后再在Java中载入这个库dll/so,最后编写Java native函数作为链接库中函数的代理,步骤非常繁琐。

223

jna

JNA是建立在JNI技术基础之上的一个Java类库,它使您可以方便地使用java直接访问动态链接库中的函数。

原来使用JNI,你必须手工用C写一个动态链接库,在C语言中映射Java的数据类型。

JNA中,它提供了一个动态的C语言编写的转发器,可以自动实现Java和C的数据类型映射,你不再需要编写C动态链接库。

224

原理

java调用go库的原理就是go使用cgo工具生成c的动态库给jna使用。

jna 类型映射关系

C TypeNative RepresentationJava Type
char8-bit integerbyte
int32-bit integerint
intboolean flagboolean
float32-bit floating pointfloat
double64-bit floating pointdouble
pointer (e.g. void*), array32- or 64-bit pointer to memory (argument/return)
contiguous memory (struct member)

[] (array of primitive type)

const char*NUL-terminated array (native encoding or jna.encoding)String
struct*
struct
pointer to struct (argument or return) (or explicitly)
struct by value (member of struct) (or explicitly)
Structure

实例

go 函数

//export add
func add(a, b C.int) C.int {
	aGo := int(a)
	bGo := int(b)
	res := aGo + bGo
	return C.int(res)
}

//export hello
func hello(name *C.char) *C.char {
	data := C.GoString(name)
	cs := C.CString("Hello " + data + "!")
	return cs
}

//export freePoint
func freePoint(cs *C.void) {
	C.free(unsafe.Pointer(cs))
}

func main() {}

生成库

如果是windows系统,则编译命令为:

go build -buildmode=c-shared -o test.dll .\test1.go

如果是linux系统,则编译命令为:

go build -buildmode=c-shared -o libtest.so .\test1.go

java 接口定义

创建一个java中的interface来映射动态库,之后我们就可以通过该 interface 的实例来访问动态库中的一些函数。

public interface AuthLibrary extends Library {

    AuthLibrary INSTANCE = Native.load("awesome", AuthLibrary.class);

    int add(int a, int b);

    Pointer hello(Pointer name);

    void freePoint(Pointer pointer);
}

java调用接口

public class AuthServer {
      public static String hello(String name) {
        // 申请jna的内存空间
        Pointer p = new Memory(name.getBytes(StandardCharsets.UTF_8).length + 1);
        // 设置传入参数值
        p.setString(0, name);
        Pointer ptr = null;
        try {
            ptr = AuthLibrary.INSTANCE.hello(p);
            return ptr.getString(0, "utf8");
        } finally {
            // 释放传入jna的指针对应的内存空间
            Native.free(Pointer.nativeValue(p));
            // 解决多次调用崩溃的问题
            Pointer.nativeValue(p, 0);
            if (ptr != null) {
                // 释放go中申请的C的内存
                AuthLibrary.INSTANCE.freePoint(ptr);
            }
        }
    }
    
    private static void freeJna(Pointer pointer) {
        // 释放传入jna的指针对应的内存空间
        Native.free(Pointer.nativeValue(pointer));
        // 解决多次调用崩溃的问题
        Pointer.nativeValue(pointer, 0);
    }
}

测试

public class JNATest {

    public static void main(String[] args) {
        System.out.println(AuthLibrary.INSTANCE.add(1, 2));
        int count = 1;
        for (int i = 0; i < count; i++) {
            String msg = "测试 java -> go,java -> go,java -> go,java -> go,java -> go,java -> go,java -> go,java -> go";
            System.out.println(AuthServer.hello(msg));
        }
        count = 999999999;
}

结果

C.CString会malloc一个空间,需要释放,不释放则会内存泄漏。

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×