天天看點

Java調用本地方法又是怎麼一回事

JNI即Java Native Interface,它能在Java層實作對本地方法的調用,一般本地的實作語言主要是C/C++,其實從虛拟機層面來看JNI挺好了解,JVM主要使用C/C++ 和少量彙編編寫,在執行Java位元組碼時如果遇到有某個方法标明為Native的則從JVM中找到對應的C/C++函數,一般本地方法對應的函數會被注冊到JVM中。

使用JNI能讓Java與本地語言互動,但一般也意味着喪失了跨平台性,而有些場合會使用。比如标準的Java特性不符合你的需求時,比如在性能要求很高的某段邏輯。

編寫一個Java類提供本地加密的方法,其中加密方法為本地方法,實作是在ByteCodeEncryptor動态庫。

為友善起見,不自己寫頭檔案,用<code>javah -jni com.seaboat.bytecode.ByteCodeEncryptor</code>生成。

編寫源檔案,實作頭檔案聲明的函數。

用cl進行編譯,生成動态庫,指定編譯需要的一些頭檔案。

可以調用Java層的ByteCodeEncryptor類的encrypt方法了。

Java層需要調用<code>System.loadLibrary</code>去加載動态庫,而它其實就是通過<code>ClassLoader</code>的<code>loadLibrary</code>方法來加載,加載的大緻邏輯為:

是不是使用了絕對路徑來指定動态庫,如果是則直接通過絕對路徑來加載。

如果啟動Java時帶有<code>-Dsun.boot.library.path=xxxx</code>時,則去改參數指定的目錄下尋找動态庫。

如果啟動Java時帶有<code>-Djava.library.path=xxxx</code>時,則去改參數指定的目錄下尋找動态庫。

加載動态庫在Java層面實作不了,是以必須會通過本地才能真正實作加載操作,Java層面最後是走到<code>NativeLibrary</code>類,其包含的<code>load</code>本地方法為真正的加載注冊操作。

對應着<code>ClassLoader.c</code>的Java_java_lang_ClassLoader_00024NativeLibrary_load函數,因為NativeLibrary在Java層的ClassLoader的子類,是以其中包含一串數字<code>00024</code>,即表示美元符号。該函數最重要的一步是調了<code>JVM_LoadLibrary</code>函數,該函數如下,核心的一步是<code>os::dll_load</code>,它會根據不同的作業系統做不同的處理。

看一個圖,它包含了<code>linux</code>、<code>solaris</code>、<code>windows</code>三大類型作業系統的處理,下面分别看看不同作業系統如何處理。

Java調用本地方法又是怎麼一回事

對于linux,主要通過<code>dlopen</code>函數來打開動态庫,并加載到記憶體中,再通過dlsym函數可以擷取動态庫中的函數指針,于是就能實作調用動态庫某函數。

對于solaris,主要通過<code>dlopen</code>函數來打開動态庫,并加載到記憶體中,再通過dlsym函數可以擷取動态庫中的函數指針,但它與linux不同的是dlsym在linux中是非線程安全的,需要加鎖,而solaris則不需要。

對于windows,主要通過<code>LoadLibrary</code>函數加載動态庫,加載到記憶體中,再通過GetProcAddress函數可以擷取動态庫的函數指針,進而實作調用動态庫某函數。

另外,我們注意到Java層不必指定動态庫的字尾,這個留給JVM去解決,它會根據不同作業系統添加不同的字尾,這個邏輯由<code>System.c</code>的<code>Java_java_lang_System_mapLibraryName</code>函數實作,它會有如下兩個字尾。

對于位元組碼,它是Java執行時的指令,其實想一下就能想到本地方法要在執行時差別于Java層的調用,是以必須要有一個flag來辨別本地方法,那咱們用javap來看看上面包含本地方法的class會有什麼辨別,可以看到存在一個<code>ACC_NATIVE</code>,有了它就可以在執行時調用C/C++函數了。

兩句話總結起來就是,Java編譯器将包含本地方法的class對應的方法添加<code>ACC_NATIVE</code>辨別,而JVM負責将動态庫加載到記憶體,Java執行引擎執行到本地方法時找到對應的函數,完成本地方法的調用。

以下是廣告和相關閱讀

========廣告時間========

<a href="http://blog.csdn.net/wangyangzhizhou/article/details/74080321">為什麼寫《Tomcat核心設計剖析》</a>

=========================

相關閱讀:

<a href="http://blog.csdn.net/wangyangzhizhou/article/details/72699267">注解的原理又是怎麼一回事</a>

歡迎關注:

Java調用本地方法又是怎麼一回事