深入理解OSGi類載入機制

Camork發表於2019-02-16

      OSGi之所以能夠實現模組熱插拔和模組內部可見性的精準控制都歸結於其特殊的類載入機制.載入器之間的關係不再是雙親委派模型的樹狀結構,而是發展成複雜的網狀結構。

       根據OSGi規範說明:

對於類或資源載入,框架必須遵循以下規則。 當請求bundle的類載入器載入類或資源時,必須按以下順序執行搜尋:

  1. 如果類或資源在java.*包中,則將請求委託給父類載入器; 否則,繼續下一步搜尋。 如果請求被委託給父類載入器還找不到類或資源,則搜尋終止並且失敗。
  2. 如果類或資源來自引導委派列表(系統變數org.osgi.framework.bootdelegation)中包含的包,則將請求委託給父類載入器。如果在那裡找不到類或資源,繼續下一步搜尋。
  3. 如果類或資源屬於宣告在Import-Package匯入的包中,或者是在先前的載入中動態匯入的,那麼請求將委託給宣告Export-Package這個包的bundle的類載入器;否則繼續下一步搜尋。如果請求被委託給匯出類載入器但找不到類或資源,則失敗。
  4. 如果類或資源位於在多個Require-Bundle包中匯入的包中,則請求將按照清單中指定的順序委派給其他包的類載入器。這個過程中使用深度優先策略;如果未找到類或資源,則繼續下一步搜尋。
  5. 搜尋bundle的內嵌jar的類路徑(Bundle Class Path)。如果找不到類或資源,繼續下一步。
  6. 查詢Bundle的Fragment Bundle中匯入的包, 如果沒找到繼續下一步
  7. 如果類或資源位於自己匯出的包中,則搜尋結束並失敗。
  8. 否則,如果類或資源位於DynamicImport-Package匯入的包中,則嘗試動態匯入包。
  9. 如果動態匯入包成功,則將請求委託給匯出這個包的類載入器。如果請求被委託給匯出類載入器並且找不到類或資源,則搜尋終止且失敗。

總體圖:  

深入理解OSGi類載入機制

     但這種模式也會產生許多隱患,比如迴圈依賴問題,如果BundleA依賴BundleB , BundleB依賴BundleC, BundleC又依賴BundleA, 這可能在載入Bundle的時候導致死鎖問題。為了避免這種情況,根據OSGi規範說明,在這種情況下,框架必須在第一次訪問Bundle的時候做標記,不去訪問已經訪問過的Bundle.

     另外,在OSGi中Bundle都有自己獨有的ClassLoader, Fragment Bundle不同於普通Bundle, 其和其附著的Host Bundle共享一個ClassLoader.

如果在開發Liferay的過程中遇到Unresolved import-Package問題,可以參考我在Liferay的一篇部落格Never get into trouble with 'Unresolved requirement' again

參考文獻

  1. 深入理解Java虛擬機器第三版(周志明)

  2. OSGi Specification


 


相關文章