在他的 最近的部落格文章中,Glyn 介紹了 OSGi “uses” 指令。 在本部落格中,我想更深入地探討 uses 限制違規的原因,並提供一些診斷應用程式中 uses 問題的技巧。
對於大部分範例,我將使用原始 Equinox,而不是 dm Server。 原因是 uses 限制並非特定於 dm Server,而是與所有 OSGi 使用者相關。 在本部落格的結尾,我將示範一些建置到 dm Server 中的智慧型限制失敗診斷。
相依限制不符
Uses 違規最常見的原因是相依限制之間的一個或多個不符。 作為範例,請考慮以下三個資訊清單
Manifest-Version: 1.0
Bundle-Name: Spring Bundle
Bundle-ManifestVersion: 2
Bundle-SymbolicName: spring
Bundle-Version: 2.5.5
Export-Package: spring.orm.hibernate;version="2.5.5";uses:="eclipselink"
Import-Package: eclipselink;version="[1.0, 2.0)"
Manifest-Version: 1.0
Bundle-Name: EclipseLink 1 Bundle
Bundle-ManifestVersion: 2
Bundle-SymbolicName: eclipselink
Bundle-Version: 1
Export-Package: eclipselink;version="1.0.0"
Manifest-Version: 1.0
Bundle-Name: EclipseLink 2 Bundle
Bundle-ManifestVersion: 2
Bundle-SymbolicName: eclipselink
Bundle-Version: 2
Export-Package: eclipselink;version="2.0.0"
在這裡,您可以看到一個 spring 綁定和兩個 eclipselink 綁定。 顯然,這些不是真正的綁定。 spring 綁定匯入了 eclipselink 套件,範圍為 [1.0, 2.0)。 顯然,只有 eclipselink_1 綁定可以滿足此限制。 現在,請考慮來自兩個不同應用程式的這些資訊清單
Manifest-Version: 1.0
Bundle-Name: App1 Bundle
Bundle-ManifestVersion: 2
Bundle-SymbolicName: app1
Bundle-Version: 1.0.0
Import-Package: spring.orm.hibernate,eclipselink;version="[1.0, 1.0]"
Manifest-Version: 1.0
Bundle-Name: App2 Bundle
Bundle-ManifestVersion: 2
Bundle-SymbolicName: app2
Bundle-Version: 1.0.0
Import-Package: spring.orm.hibernate,eclipselink;version="[2.0, 2.0]"
在這裡,我們可以看到 app1 匯入了 eclipselink,範圍為 [1.0, 1.0],而 app2 匯入了 eclipselink,範圍為 [2.0, 2.0]。 如果我將這些綁定安裝到 Equinox 中,然後嘗試啟動應用程式綁定,則控制台會顯示如下內容
id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.0.v20080605-1900
2 RESOLVED spring_2.5.5
3 RESOLVED eclipselink_1.0.0
4 RESOLVED eclipselink_2.0.0
5 ACTIVE app1_1.0.0
6 INSTALLED app2_1.0.0
在這裡,我們可以看到 spring 和 eclipselink 綁定都已解析。 app1 綁定已啟動,但 app2 綁定無法啟動。 為了找出原因,我們可以使用 diag 命令
osgi> diag app2
file:/Users/robharrop/dev/resdiag/uses/app2/bin [6]
Package uses conflict: Import-Package: spring.orm.hibernate; version="0.0.0"
在這裡,我們可以看到 app2 綁定無法解析,因為其匯入的 spring.orm.hibernate 存在套件 uses 衝突。 這表示 app2 中匯入的 spring.orm.hibernate 無法滿足,因為其另一個匯入與可以提供 spring.orm.hibernate 的綁定上的 uses 限制衝突 - 在這種情況下為 spring 綁定。
診斷此問題的第一步是找出 spring.orm.hibernate 綁定的可能供應商。 我們從我們的使用案例中知道,唯一可能的供應商是 spring 綁定,但如果您不知道供應商,則可以使用 packages 命令找到它們
osgi> packages spring.orm.hibernate
spring.orm.hibernate; version="2.5.5"<file:/Users/robharrop/dev/resdiag/uses/spring/bin [2]>
file:/Users/robharrop/dev/resdiag/uses/app1/bin [5] imports
這告訴我們 spring.orm.hibernate 套件由綁定 2 匯出。 透過此知識,我們可以找出 spring.orm.hibernate 套件在綁定 2 的 uses 指令中列出了哪些套件
osgi> headers 2
Bundle headers:
Bundle-ManifestVersion = 2
Bundle-Name = Spring Bundle
Bundle-SymbolicName = spring
Bundle-Version = 2.5.5
Export-Package = spring.orm.hibernate;version="2.5.5";uses:="eclipselink"
Import-Package = eclipselink;version="[1.0, 2.0)"
Manifest-Version = 1.0
在這裡,我們可以看到 uses 中唯一的套件是 eclipselink 套件,因此它一定是罪魁禍首。 實際上,我們可以看見 Spring 綁定需要在範圍 [1.0, 2.0) 中的 eclipselink,而 app2 需要在範圍 [2.0, 2.0] 中的 eclipselink - 這兩個範圍是不相交的,這意味著 app2 無法 連接到與 spring 綁定相同的 eclipselink 版本。
如果 uses 清單很長,您可以透過找出哪些列出的套件具有多個供應商來縮小可能的違規。 必須始終有多個供應商才能看到 uses 限制違規。
版本不符不是相依限制不符的唯一原因。 由於屬性和版本,限制可能不符。
安裝順序問題
如果我們重新檢視先前的範例並變更 spring 綁定的資訊清單,以便它可以接受版本 2.0 的 eclipselink 套件並放寬 app1 的範圍,以便它可以接受 1.0 以上的任何版本,我們應該能夠修正問題
Manifest-Version: 1.0
Bundle-Name: Spring Bundle
Bundle-ManifestVersion: 2
Bundle-SymbolicName: spring
Bundle-Version: 2.5.5
Export-Package: spring.orm.hibernate;version="2.5.5";uses:="eclipselink"
Import-Package: eclipselink;version="[1.0, 2.0]"
Manifest-Version: 1.0
Bundle-Name: App1 Bundle
Bundle-ManifestVersion: 2
Bundle-SymbolicName: app1
Bundle-Version: 1.0.0
Import-Package: spring.orm.hibernate,eclipselink;version="1.0"
安裝綁定並啟動應用程式綁定表明此變更會產生很大的影響
id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.0.v20080605-1900
1 RESOLVED spring_2.5.5
2 RESOLVED eclipselink_1.0.0
3 RESOLVED eclipselink_2.0.0
4 ACTIVE app1_1.0.0
5 ACTIVE app2_1.0.0
現在,兩個應用程式綁定都可以啟動。 不幸的是,還有一個更微妙的問題在等待著我們。 根據安裝順序,這組綁定可能仍然無法一起執行。 為了說明這一點,讓我們以一個交易安裝 spring、eclipselink_1 和 app1 並啟動 app1
id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.0.v20080605-1900
1 RESOLVED spring_2.5.5
2 RESOLVED eclipselink_1.0.0
3 ACTIVE app1_1.0.0
現在,讓我們安裝 eclipselink_2 和 app2
id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.0.v20080605-1900
1 RESOLVED spring_2.5.5
2 RESOLVED eclipselink_1.0.0
3 ACTIVE app1_1.0.0
4 RESOLVED eclipselink_2.0.0
5 INSTALLED app2_1.0.0
app2 綁定無法啟動。 diag 的輸出告訴我們原因
osgi> diag app2
file:/Users/robharrop/dev/resdiag/uses/app2/bin [5]
Package uses conflict: Import-Package: spring.orm.hibernate; version="0.0.0"
uses 限制已恢復。 執行先前章節中識別的診斷步驟無濟於事,因為沒有相依限制不符 - 我們知道這一點,因為第一次這些綁定已正常解析。
這裡的問題在於解析順序。這些套件是以兩個不同的區塊安裝和解析的。第一個區塊包含 spring、eclipselink_1 和 app1,第二個區塊包含 eclipselink_2 和 app2。當第一個區塊解析時(因為啟動 app1 套件),spring 套件會連接到 eclipselink_1 套件,以滿足它對 eclipselink 套件的匯入。這可以使用主控台來確認
osgi> bundle app1
file:/Users/robharrop/dev/resdiag/uses/app1/bin [3]
Id=3, Status=ACTIVE Data Root=/opt/springsource-dm-server-1.0.0.RELEASE/lib/configuration/org.eclipse.osgi/bundles/3/data
No registered services.
No services in use.
No exported packages
Imported packages
spring.orm.hibernate; version="2.5.5"<file:/Users/robharrop/dev/resdiag/uses/spring/bin [1]>
eclipselink; version="1.0.0"<file:/Users/robharrop/dev/resdiag/uses/eclipselink1/bin [2]>
No fragment bundles
Named class space
app1; bundle-version="1.0.0"[provided]
No required bundles
請注意,匯入的套件區段顯示 eclipselink 版本 1.0.0 是從 eclipselink_1 套件匯入的。當第二個區塊安裝時,app2 套件無法解析,因為它需要 eclipselink 版本 2.0.0,但 spring 已經連接到 eclipselink 版本 1.0.0。當所有套件作為一個區塊安裝和解析時,OSGi 解析器將嘗試滿足所有約束,包括確保可以滿足 spring.orm.hibernate 上的 uses 約束。
為了修正這個問題,我們不需要更改我們的套件。相反,我們可以重新安裝這些套件在一個區塊中,或者我們可以對 spring 套件觸發刷新 - 有效地要求 OSGi 重新運行解析過程。現在 eclipselink_2 套件已經安裝,我們可以預期這會有不同的結果
osgi> refresh spring
osgi> ss
Framework is launched.
id State Bundle
0 ACTIVE org.eclipse.osgi_3.4.0.v20080605-1900
1 RESOLVED spring_2.5.5
2 RESOLVED eclipselink_1.0.0
3 ACTIVE app1_1.0.0
4 RESOLVED eclipselink_2.0.0
5 ACTIVE app2_1.0.0
osgi> bundle spring
file:/Users/robharrop/dev/resdiag/uses/spring/bin [1]
Id=1, Status=RESOLVED Data Root=/opt/springsource-dm-server-1.0.0.RELEASE/lib/configuration/org.eclipse.osgi/bundles/1/data
No registered services.
No services in use.
Exported packages
spring.orm.hibernate; version="2.5.5"[exported]
Imported packages
eclipselink; version="2.0.0"<file:/Users/robharrop/dev/resdiag/uses/eclipselink2/bin [4]>
No fragment bundles
Named class space
spring; bundle-version="2.5.5"[provided]
No required bundles
請注意,刷新 spring 導致 app2 套件得以解析。spring 中 eclipselink 套件的連接已經更改,由 eclipselink_2 套件匯出的版本 2.0.0 來滿足。
dm Server 中的 Uses 約束
當您在 dm Server 中遇到 uses 約束衝突時,我們已經嘗試為您執行一些分析步驟,特別是識別可能不匹配的相依約束
Could not satisfy constraints for bundle 'app2' at version '1.0.0'.
Cannot resolve: app2
Resolver report:
Bundle: app2_1.0.0 - Uses Conflict: Import-Package: spring.orm.hibernate; version="0.0.0"
Possible Supplier: spring_2.5.5 - Export-Package: spring.orm.hibernate; version="2.5.5"
Possible Conflicts: eclipselink
Uses 約束在企業函式庫中很常見,手動診斷故障可能是一場真正的噩夢。特別是,當您有一個匯出的套件,並且在其 uses 子句中列出了 10 個或更多套件時,確定可能的衝突可能非常耗時。因此,自動診斷是必須的,我希望不斷改進 dm Server 中的診斷程式碼,以便處理常見錯誤變得微不足道。
在下一個版本中,我們計劃將診斷工具直接構建到我們的 dm Server Eclipse 工具中,以便大多數這些問題將由 dm Server 自動診斷。