我正在開發一個使用JNI調用Java類的PHP5擴展。這樣做的擴展和核心功能已經準備就緒,並且在單線程(每個進程)環境中按預期工作。因此,在命令行(php-cli)上使用php腳本中的擴展類功能沒有任何問題。 現在使用該PHP擴展作爲apache模塊,在通過JNI創建JVM時遇到問題。使用該模塊的第一個調用工作正常,第二個調用(在第一個調用運行時以及在第一個調用完成後),JVM不會創建並返回一個小於0的代碼(JNI_ERR
)。正如我發現的那樣,每個進程一次只能有一個JVM是一個限制。我測試並運行我的模塊運行Apache只有一名工人(使用-X
開關)。使用JVM構建PHP擴展,需要實現思路
我在現階段模塊的設計是這樣的:
- 擴展構造函數創建JVM,使一些初始化。
- 然後我有幾個方法來調用和使用java類(如傳遞參數等),並執行一些java類的方法。
- 我的擴展析構函數釋放了所有使用的資源,並銷燬了以前在構造函數中創建的JVM。
那麼,首先我想說,一切都會解決,但事實並非如此。不像現在這樣實施。所以我有點卡在想法如何解決這個問題。
我的問題是: 我應該在哪裏創建JVM,以及如何在線程環境(PHP作爲Apache模塊)中正確調用它(JNI Env)。我想我必須在模塊初始化時使用JNI_CreateJavaVM
在某處創建JVM,然後使用AttachCurrentThread
/DetachCurrentThread
?!如果另一個線程試圖連接到JVM線程,但是已經有另一個線程連接到它,會發生什麼?我必須在這裏做一些鎖定機制嗎?或者在擴展類方法中創建JVM,在該方法內調用所有與Java相關的方法,並在同一擴展類方法的末尾銷燬JVM?我根本不喜歡這個想法。儘管我認爲它不能解決每個進程有多個JVM的問題。
我希望事情不要太複雜。
所以,基本上,我的問題是在哪裏實現JVM創建/銷燬調用以及如何訪問JNI環境來調用Java類方法。最後但並非最不重要的是,無論如何可能我試圖完成什麼?
一些開發細節:我的平臺是Linux/Ubuntu Lucid 10.04 LTS,使用Apache2和PHP 5.2.16(從源代碼編譯)。模塊和核心功能是用C開發的,Java JRE是6.0.22(Oracle下載)。
感謝您的回答!你的建議聽起來似乎合理。當Apache啓動時,它調用PHP_MINIT_FUNTION函數,在那裏我想我可以創建JVM。在Apache關閉時,調用PHP_MSHUTDOWN_FUNCTION。我將Zend對象存儲用於所有與對象有關的變量,這裏也是存儲在結構中的JVM句柄(除了Env句柄)。它應該是線程安全的。所以如果我理解正確的話,每當我想在擴展的類方法中使用JVM時,我只需附加到該JVM,調用Java的東西並在方法內分離?不需要創建額外的線程,對嗎? – 2011-03-15 06:17:18
Apache使用線程或分叉進程。因此,函數總是不可能從同一個線程中調用。附加和分離可能相當昂貴,所以我會避免每個函數調用。 – 2011-03-15 15:28:34
這個建議似乎工作到目前爲止。我在'php_minit'中創建JVM,並在'php_mshutdown'中銷燬它。 JVM對象被定義爲全局的(我不認爲,我需要關心模塊啓動/關閉時的線程安全性)。模塊類的構造函數然後附加到JVM並且析構函數再次分離。 JVM JNI相關對象(JNIEnv等)存儲在一個結構中,並由zend對象存儲安全地處理。好像我可以調用幾個php類的方法(我的JNI Java fct的包裝)沒有任何問題。它還沒有完成,但至少我沒有得到Apache的segfaults到現在。 – 2011-03-18 09:53:59