JNI通过动态注册实现native函数

一、概述
通过javah工具将java代码中的native声明的函数生成标准的C/C++函数头,每个函数的名字都很长(Java_包名_类名_函数名),这样C/C++函数的函数名就是定死的,不能修改,否则java找不到函数。这里还有种方式,通过注册的方式将C/C++的函数与java中的native函数进行一一对应的,函数名可以任意书写。

二、代码实现
SimpleJni.java

package com.bt.jni;
 
public class SimpleJni {
 
 static {
  System.out.println("[java]static code block, start load shared library....");
  System.loadLibrary("simpleJni");
  System.out.println("[java]load library end....");
 }
 
 static native int add(int a, int b);
 
 public static void main(String args[]) {
  System.out.println("[java] in main()...");
  System.out.println("[java] 3 + 5 = " + SimpleJni.add(3, 5));
  System.out.println("[java] main() end...");
 }
 
}

simple_jni.c
#include "jni.h"
#include <stdio.h>
 
 
const char *classPathName = "com/bt/jni/SimpleJni";
 
/**
 native 函数的实现
**/
jint myadd(JNIEnv *env, jobject thiz, jint a, jint b)
{
 return a + b;
}
 
static JNINativeMethod methods[] = {
 //{native函数名,函数签名, C中函数实现名}
 {"add", "(II)I", (void*)myadd},
};
 
int registerNatives(JNIEnv *env)
{
 jclass clazz;
 
 //根据类的全路径,获得类的字节码信息
 clazz = (*env)->FindClass(env, classPathName);
 if (NULL == clazz) {
  printf("[C] FindClass() failed...\n");
  goto failed;
 }
 
 //将c函数与字节码中的native函数进行映射
 if (0 > (*env)->RegisterNatives(env, clazz, methods, sizeof(methods)/sizeof(methods[0]))) {
  printf("[C] RegisterNatives() failed...\n");
  goto failed;
 }
 
 return JNI_TRUE;
 
failed:
 return JNI_FALSE;
}
 
/**
 java 在加载动态库的时候,自动调用此函数,注册native函数
**/
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
 JNIEnv *env = NULL;
 jint result = -1;
 void **env_p = NULL;
 
 printf("[C] start register native func...\n");
 
 env_p = (void**)&env;
 
 //首先从java虚拟机中获得env
 if (JNI_OK != (*vm)->GetEnv(vm, env_p, 0x00010004)) {
  printf("[C] GetEnv() failed...will exit\n");
  goto err;
 }
 
 //通过env进行函数的注册
 if (JNI_TRUE != registerNatives(env)) {
  printf("[C] register func failed...will exit\n");
  goto err;
 }
 
 result = 0x00010004;
 printf("[C] register end...\n");
err:
 return result;
}

操作步骤
    1.首先编写SimpleJni.java和simpel_jni.c
    2.编译java和c文件
$ java -d .  SimpleJni.java
$gcc -fPIC -I$JAVA_HOME/include/ -I$JAVA_HOME/include/linux/ -o libsimpleJni.so simple_jni.c

3.执行
    $java -Djava.library.path=. com.bt.jni.SimpleJni

结果:
    [java]static code block, start load shared library....
    [C] start register native func...
    [C] register end...
    [java]load library end....
    [java] in main()...
    [java] 3 + 5 = 8
    [java] main() end...

根据结果可知,java首先执行静态代码块,其中在加载动态库的时候,自动调用JNI_OnLoad函数,建立native函数和c中的函数映射关系,最后进入main函数。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/824e6f3dee2ad8487eba47578628bf15.html