[toc]
什么是JNI?#
JNI即Java Native Interface(Java本地接口)
是一个协议,主要作用为:实现Java调用c/c代码(类库),或者C/C调用Java代码
JNI应用步骤#
- 首先定义java类
- 类里需要有一个native关键字的方法
- 静态代码块加载一个C++生成的dll
1 | //JNI.java文件 |
-
使用javac 编译JNI.java生成字节码文件JNI.class
-
使用javah 编译JNI.class, 将class文件转成头文件
头文件中包含了call方法的声明
-
编写cpp文件,实现头文件中的call方法
1 | //JNIdll.cpp文件 |
-
将java目录下的include目录下的两个文件jni.h和jni_md.h(jni_md.h在include目录下的win32目录中)拷贝到vc的include目录下, 好让C++环境支持jni
-
用C/C++编译命令编译cpp和h文件,生成dll动态链接库
JNI的底层原理#
-
jvm调用native方法时, 其方法指针nativeFunc默认先指向resolveNativeMethod方法
-
resolveNativeMethod方法中, 是一段通用的实现代码
首先,判断这个方法如果是静态方法,首先确保所属的class已经初始化,否则会报错
-
接着先在内部本地方法表中查询。
内部本地方法表是一个集合,这个集合里包含了java语言和虚拟机本身用到的所有native方法
根据类描述符的hash值从集合中寻找对应的方法
如果找到了,就修改nativeFunc的指针,指向对应方法 -
如果内部本地方法表里没找到, 才会通过System.loadLibrary加载的so,虚拟机会将所有的so存入一个表中
gDvm.nativeLibs是一个HashTable,其中存的是动态链接库的信息。其中的数据是通过System.loadLibrary添加进去的。
① 检查是否已经加载过该so,如果是还需要判断加载so的classLoader是否相同,不同的话也会报错,
②如果没有加载过,则使用dlopen打开so,然后创建一个ShareLib加入到gDvm.nativeLibs哈希表中。
③如果so中有JNI_OnLoad方法,则执行该方法。我们可以在该方法中做一些初始化工作,还可以手动建立java类中的native方法和so中的native方法的对应关系。