博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java JNI 实现原理 (二) Linux 下如何 load JNILibrary
阅读量:7125 次
发布时间:2019-06-28

本文共 3214 字,大约阅读时间需要 10 分钟。

在博客java JNI (一) 中classloader的JNILibrary 中讨论了java中的Library 是由classloader 来load的,那我们来看看 classloader是如何去load 一个library的。

 

ClassLoader.c  

 

[cpp]  

JNIEXPORT void JNICALL   Java_java_lang_ClassLoader_00024NativeLibrary_load    (JNIEnv *env, jobject this, jstring name)  {      const char *cname;      jint jniVersion;      jthrowable cause;      void * handle;        if (!initIDs(env))          return;        cname = JNU_GetStringPlatformChars(env, name, 0);      if (cname == 0)          return;      handle = JVM_LoadLibrary(cname);      if (handle) {          const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;          JNI_OnLoad_t JNI_OnLoad;      int i;      for (i = 0; i < sizeof(onLoadSymbols) / sizeof(char *); i++) {          JNI_OnLoad = (JNI_OnLoad_t)               JVM_FindLibraryEntry(handle, onLoadSymbols[i]);          if (JNI_OnLoad) {              break;          }      }      if (JNI_OnLoad) {          JavaVM *jvm;          (*env)->GetJavaVM(env, &jvm);          jniVersion = (*JNI_OnLoad)(jvm, NULL);      } else {          jniVersion = 0x00010001;      }        cause = (*env)->ExceptionOccurred(env);      if (cause) {          (*env)->ExceptionClear(env);          (*env)->Throw(env, cause);          JVM_UnloadLibrary(handle);          goto done;      }           if (!JVM_IsSupportedJNIVersion(jniVersion)) {          char msg[256];          jio_snprintf(msg, sizeof(msg),               "unsupported JNI version 0x%08X required by %s",               jniVersion, cname);          JNU_ThrowByName(env, "java/lang/UnsatisfiedLinkError", msg);          JVM_UnloadLibrary(handle);          goto done;      }      (*env)->SetIntField(env, this, jniVersionID, jniVersion);      } else {      cause = (*env)->ExceptionOccurred(env);      if (cause) {          (*env)->ExceptionClear(env);          (*env)->SetLongField(env, this, handleID, (jlong)NULL);          (*env)->Throw(env, cause);      }      goto done;      }      (*env)->SetLongField(env, this, handleID, ptr_to_jlong(handle));     done:      JNU_ReleaseStringPlatformChars(env, name, cname);  }

 

1. JVM_LoadLibrary 

jvm中load library 核心函数,实现也非常简单,在linux下调用了函数dlopen去打开库文件,详细可参考方法

 [cpp]  

void * os::dll_load(const char *filename, char *ebuf, int ebuflen)

 

2. JVM_FindLibraryEntry 

JVM在加载库文件时候,会去尝试查找库中的JNI_ONLOAD方法的地址,而在中调用了dlsym函数通过前面的dlopen加载库的指针去获取方法的地址,而dlsym在glibc2.0是非线程安全的,需要锁的保护,虽然在java中加载库已经有锁的保护,但只是针对同一个classloader对象的细粒度锁。

[cpp]  

void* os::dll_lookup(void* handle, const char* name) {    pthread_mutex_lock(&dl_mutex);    void* res = dlsym(handle, name);    pthread_mutex_unlock(&dl_mutex);    return res;  }

 

3. 方法JNI_OnLoad

JVM提供了一种方式允许你在加载库文件的时候做一些你想做的事情,也就是JNI_OnLoad方法

 

在2中提到过在加载动态链接库,JVM会去尝试查找JNI_OnLoad方法,同时也会调用该函数,这样你个人可以在函数里做一些初始化的事情,比如register native方法。

 

[cpp] 

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)  {}

 

JNI_OnLoad中返回的是JNI 的version,在1.6版本的情况下支持如下 

[cpp]  

jboolean Threads::is_supported_jni_version(jint version) {    if (version == JNI_VERSION_1_2) return JNI_TRUE;    if (version == JNI_VERSION_1_4) return JNI_TRUE;    if (version == JNI_VERSION_1_6) return JNI_TRUE;    return JNI_FALSE;  }

 

完整的加载过程就是

 

首先先加载动态链接库,尝试查找JNI_OnLoad方法,并且运行方法,对我们来说从而实现可以自定义的初始化方法。

 

 

转载于:https://www.cnblogs.com/yelao/p/9592315.html

你可能感兴趣的文章
Webpack快速入门
查看>>
HandlerThread与AsyncQueryHandler源码分析
查看>>
caffe原理之softmax函数
查看>>
数据分组统计
查看>>
记录fastclick中一次手动触发click事件失败
查看>>
云框架发布KONG API Gateway主题,开源求助攻~
查看>>
从一次报错聊聊 Point 事件
查看>>
JS attribute and prpperty
查看>>
SpringMVC配置太多?试试SpringBoot
查看>>
详解js深浅复制
查看>>
Laravel 服务容器实现原理
查看>>
stl map
查看>>
什么是with?
查看>>
LeetCode Weekly Contest 21
查看>>
查询计划参数详解
查看>>
JS中把对象赋值给变量时出现的问题
查看>>
华为敏捷/DevOps实践:如何开好迭代计划会议
查看>>
AI+社交,快手商业化落地之道
查看>>
.NET Core中的去虚
查看>>
滴滴开源支撑业务代码重构工具Rdebug
查看>>