當前位置:
首頁 > 知識 > Java Web項目中使用JNI技術

Java Web項目中使用JNI技術

記錄結構:

JNI技術入門詳解,

注意:手記與接下來要記錄的網站項目中使用JNI技術是無縫連接的。

應用場景:當我們根據不同的平台生成不同的JNI libaray時,例如:linux .so,mac jnilib,windows .dll。我們想在打包web應用時讓程序動態調用c,或者c ++對Java Native Inteface的具體底層實現時,有一種方法是藉助配置在想法中的vm選項中設置庫文件所在的路徑,即-Djava.path.library,剛哥手記最後一部分有說明。

精準定位問題:

那麼有沒有另外一種方式使得Java程序在調用native inteface中抽象本地方法自動載入所需要的代碼呢?也就是說應用程序自動載入.so || (或) .jnilib || .dll?

2.我們知道Java應用程序在調用底層代碼生成的庫文件時,需要指定庫文件所在的路徑。那麼我們的問題就清晰了,問題的痛點在於如何讓應用程序在程序運行期間動態載入庫文件所在的路徑,進而載入所需的庫文件。

網上的一種說法是:在使用的System.loadLibrary( 「具體庫文件所在的路徑的相對路徑」),之前使用System.load(「具體庫文件所在的根目錄的全路徑「),本人試了一下,發現並不起作用。

系統屬性指示JVM在哪裡搜索本機庫。您必須使用-Djava.library.path = / path / to / lib將其指定為JVM參數

,然後當您嘗試使用System.loadLibrary(「foo」)載入庫時

,JVM將搜索庫路徑指定的庫。如果找不到你會得到一個例外:

大致的意思是:

系統屬性 - java.library.path指引JVM去尋找底層的庫文件,你必須為JVM聲明一個屬性,類似於Djava.library.path = / path / to / lib,當你需要使用System.loadLibrary(「foo 「)載入底層foo的庫文件的時候,JVM會按照你聲明的路徑去載入這個庫文件,如果你不聲明的話,會出現下面錯誤:

。這個錯告訴我們富並不庫在我們所要載入的路徑下面

接下來說明原因:

,則不會有任何差異。

源碼中ClassLoader.loadLibrary有這樣一句代碼:

為什麼就定位問題到上述幾行代碼,我們得從源碼的角度來分析,看下源碼:

首先是System.loadLibaray(),藉助想法看下源碼:

/ ** *載入由 libname *參數指定的本機庫。 libname 參數不能包含任何平台 *特定的前綴,文件擴展名或路徑。如果一個 名為 libname 的本地庫與VM靜態鏈接,則 調用庫導出的* JNI_OnLoad_ libname 函數。 *有關詳細信息,請參閱JNI規範。 * *否則,libname參數是從系統庫 *位置載入的,並以 實現方式映射到本機庫映像。 *

*調用 System.loadLibrary(name)有效地 等同於 * * blockquote>

* Runtime.getRuntime()。loadLibrary(name) * * * @param libname庫的名稱。 * @exception SecurityException如果安全管理器存在,並且其 * checkLink 方法不允許 *載入指定的動態庫 * @exception如果libname參數 *包含文件路徑,本地庫不是 與虛擬機靜態*鏈接,或者庫不能被 主機系統映射到*本機庫映像。 * @exception NullPointerException如果 libname 是 * null * @see java.lang.Runtime#loadLibrary(java.lang.String) * @see java.lang.SecurityManager#checkLink (java.lang.String) * / @CallerSensitive public static void loadLibrary(String libname){ Runtime.getRuntime()。loadLibrary0(Reflection.getCallerClass(),libname); }

可以看到 方法調用中出現Runtime.getRuntime()。loadLibrary0(),從這行代碼我們知道庫文件是在運行時被載入起作用的。

我們繼續看loadLibrary0()

/ ** *載入由 libname *參數指定的本機庫。 libname 參數不能包含任何平台 *特定的前綴,文件擴展名或路徑。如果一個 名為 libname 的本地庫與VM靜態鏈接,則 調用庫導出的* JNI_OnLoad_ libname 函數。 *有關詳細信息,請參閱JNI規範。 * *否則,libname參數是從系統庫 *位置載入的,並以 實現方式映射到本機庫映像。 *

*首先,如果有安全管理器, 則使用 libname 作為參數調用其 checkLink *方法。 *這可能會導致安全例外。 *

*方法{@link System#loadLibrary(String)}是傳統的 *方便的方法。如果本機 *方法用於實現一個類,則標準 *策略是將本機代碼放入庫文件(調用它 * LibFile ),然後放入靜態初始化器: *

* static * *在類聲明中。當類被載入和 *初始化時,本機 *方法的必要本機代碼實現也將被載入。 *

*如果使用相同的庫 *名稱多次調用此方法,則將忽略第二個和後續調用。 * * @param libname庫的名稱。 * @exception SecurityException如果安全管理器存在,並且其 * checkLink 方法不允許 *載入指定的動態庫 * @exception如果libname參數 *包含文件路徑,本地庫不是 與虛擬機靜態*鏈接,或者庫不能被 主機系統映射到*本機庫映像。 * @exception NullPointerException如果 libname 是 * null * @see java.lang.SecurityException * @see java.lang.SecurityManager#checkLink(java.lang.String) * / @CallerSensitive public void loadLibrary(String libname){ loadLibrary0(Reflection.getCallerClass(),libname); } synchronized void loadLibrary0(Class fromClass,String libname){ SecurityManager security = System.getSecurityManager(); if(security!= null){ security.checkLink(libname); } if(libname.indexOf((int)File.separatorChar)!= -1){ throw new UnsatisfiedLinkError( 「目錄分隔符不應出現在庫名稱中:」+ libname); } ClassLoader.loadLibrary(fromClass,libname,false); }

題外話:loadLibrary(),loadLibrary0()這兩個方法的命名還是挺不符合規範的,歷史遺留問題吧。

在loadLibrary中我們看到了ClassLoader.loadLibrary(fromClass,libname,false) ;方法

繼續追溯

對於上述代碼的解釋我們可以從這篇博客中獲取到答案:

如果將sys_paths設置為null,則在嘗試載入庫時,庫路徑將被重新初始化。

那麼問題來了,通過剛才的源代碼追溯,我們知道System.loadLibray()調用ClassLoader.loadLibrary ()方法,

我們應該如何將sys_paths設置為空?

通過上述情景描述,我們要更改sys_paths的值為空,只能在sys_paths初始化之前做手腳(反射在程序動態運行期間更改程序中的屬性值)。

代碼如下:

追溯上述代碼,調試結果如下圖所示:

最終程序的正常運行。

我在網路項目中的應用是這樣的:

程序封裝,對JNI的使用封裝成jniutil工具類:

代碼如下:

注意:對庫文件的載入放置在靜態代碼塊中,

記錄完畢。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 java吧 的精彩文章:

Java抽象類使用實例解讀
Java到底是不是一種純面向對象語言?
JAVA 對象引用,以及對象賦值
從零開始學會做一個簡單的APP

TAG:java吧 |

您可能感興趣

使用 Angular CLI 搭建項目
如何在 Emacs 中使用 Magit 管理 Git 項目
谷歌或重啟Google Glass項目 融入AR技術
開源項目Safespaces想讓你在VR中使用Linux系統
Github 項目推薦 用PyTorch 實現 OpenNMT
GitHub項目 | PyTorch 中文手冊
springboot項目中使用原生jdbc連接MySQL資料庫
AT&T聯合SKT和Intel啟動Airship OpenStack項目
Blazor正式成為Microsoft官方.NET 和WebAssembly項目
基於SpringBoot的WEB API項目的安全設計
Lumia手機刷Win10 ARM項目GitHub上線
對話倫敦時尚商業孵化器 CFE 項目主管 Ishwari Thopte
即插即用 戴姆勒與Hubject、Ebee合作Plug&Charge充電項目
使用Jira software+Structure實現大規模跨團隊項目管理
GitHub 熱門項目:Python Fire
使用Visual Studio Code編譯、調試Apollo項目
為刺激VR/AR領域發展 Digital Catapult再次啟動Augmentor項目
GitHub 熱門項目:PyTorch 資源大全
Servlet+MyBatis項目轉Spring Cloud微服務,多數據配置修改建議
VMware 收編 Serverless OpenFaaS 創始人;戴爾關閉開源項目