0%

java-JNI应用

[toc]


什么是JNI?#

JNI即Java Native Interface(Java本地接口)
是一个协议,主要作用为:实现Java调用c/c代码(类库),或者C/C调用Java代码


JNI应用步骤#

  1. 首先定义java类
  • 类里需要有一个native关键字的方法
  • 静态代码块加载一个C++生成的dll
1
2
3
4
5
6
7
8
9
//JNI.java文件
public class JNI{
//创建一个native接口方法,此方法在C++代码中实现
public native int call();
//静态代码块,加载由C++代码生成的.dll动态链接文件(.dll相当于Java中的jar包吧...)
static{
System.loadLibrary("JNIdll");
}
}
  1. 使用javac 编译JNI.java生成字节码文件JNI.class
    2e3b00fcc7db910ee0cc332308f69b08448d0333

  2. 使用javah 编译JNI.class, 将class文件转成头文件
    c5a38ef4c9ca5f2aaf60ee8a01699958fe0f0ece
    头文件中包含了call方法的声明
    ef461a898064377ae54e50e2c75daac5ad35b3a3

  3. 编写cpp文件,实现头文件中的call方法

1
2
3
4
5
6
7
8
9
10
11
12
//JNIdll.cpp文件

#include<stdio.h>
#include<jni.h>
#include "JNI.h"

JNIEXPORT jint JNICALL Java_JNI_call
(JNIEnv *, jobject){
//实现代码
int i = 777;
return i;
}
  1. 将java目录下的include目录下的两个文件jni.h和jni_md.h(jni_md.h在include目录下的win32目录中)拷贝到vc的include目录下, 好让C++环境支持jni

  2. 用C/C++编译命令编译cpp和h文件,生成dll动态链接库
    7da23cd5f25cc82ce66c07e3ee06f7e09717a5f9


JNI的底层原理#

  1. jvm调用native方法时, 其方法指针nativeFunc默认先指向resolveNativeMethod方法

  2. resolveNativeMethod方法中, 是一段通用的实现代码
    首先,判断这个方法如果是静态方法,首先确保所属的class已经初始化,否则会报错
    c1b4d05e0a5342c8159fbc8187caf6c2fb514775

  3. 接着先在内部本地方法表中查询。
    内部本地方法表是一个集合,这个集合里包含了java语言和虚拟机本身用到的所有native方法
    根据类描述符的hash值从集合中寻找对应的方法
    如果找到了,就修改nativeFunc的指针,指向对应方法

  4. 如果内部本地方法表里没找到, 才会通过System.loadLibrary加载的so,虚拟机会将所有的so存入一个表中
    gDvm.nativeLibs是一个HashTable,其中存的是动态链接库的信息。其中的数据是通过System.loadLibrary添加进去的。

① 检查是否已经加载过该so,如果是还需要判断加载so的classLoader是否相同,不同的话也会报错,
②如果没有加载过,则使用dlopen打开so,然后创建一个ShareLib加入到gDvm.nativeLibs哈希表中。
③如果so中有JNI_OnLoad方法,则执行该方法。我们可以在该方法中做一些初始化工作,还可以手动建立java类中的native方法和so中的native方法的对应关系。

【源码解读】JNI的实现原理