[英]Managing OSGi Dependency Hell
更新2 :由於我的博客有點死,鏈接降級,所以你可以在這里查看文章:
我有一個maven項目,使用我的POM.XML中配置的非常有名的felix maven bundle插件,方法如下:
<packaging>bundle</packaging>
(...)
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.artifactId};singleton:=true</Bundle-SymbolicName>
<Bundle-Version>${project.version}</Bundle-Version>
<Export-Package>jlifx.*</Export-Package>
<!-- <Embed-Dependency>*</Embed-Dependency> -->
</instructions>
</configuration>
</plugin>
然后我的POM中也包含一些1級/級別的依賴項:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>5.0.0.Alpha1</version>
</dependency>
</dependencies>
現在我的問題開始了...如果我做mvn安裝我將使用它非常棒的MANIFEST.MF和我所有的,但我不會得到其他依賴捆綁包,這意味着如果我抓住我的捆綁文件並將其放在我的OSGi框架實例上我會得到類似“無法解決1.0:缺少需求[1.0] osgi.wiring.package;(&(osgi.wiring.package = etc ......”)
因此,我發現創建我的第一級依賴項包的一種方法是在我的POM中創建一個配置文件,如下所示:
<profiles>
<!-- http://www.lucamasini.net/Home/osgi-with-felix/creating-osgi-bundles-of-your-maven-dependencies -->
<!-- -Pcreate-osgi-bundles-from-dependencies bundle:wrap -->
<profile>
<id>create-osgi-bundles-from-dependencies</id>
<build>
<directory>${basedir}/bundles</directory>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.0.1</version>
<extensions>true</extensions>
<executions>
<execution>
<id>wrap-my-dependency</id>
<goals>
<goal>wrap</goal>
</goals>
<configuration>
<wrapImportPackage>;</wrapImportPackage>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
這樣當我執行mvn -Pcreate-osgi-bundles-from-dependencies bundle時:wrap我將獲得捆綁包,構造良好並且正常工作。 但是,這是真正的交易。 這些bundle也有自己的依賴關系,因此他們需要將它們的依賴關系作為bundle捆綁在一起。 根據很多網頁,很久以前我們有mvn org.apache.felix:maven-bundle-plugin:bundleall目標為我們這樣做,但我已經嘗試過,它是錯誤的並且返回異常並且被標記為已棄用根據Stuart的說法,它將在maven 2.4.1及更高版本中刪除(參考: https : //issues.apache.org/jira/browse/FELIX-4145 )。
因此,我現在唯一的解決方案是手動檢查我的第一級依賴項的每個清單,然后google查找包含所需包的jar,將它們作為maven依賴項添加到我的POM.XML中,然后運行mvn -Pcreate-osgi-bundles -from-dependencies bundle:wrap將它們包裝為bundle。
這就是所謂的依賴地獄......
有沒有辦法自動完成解決maven-bundle osgi項目的n級依賴項的任務? 即使maven研究我的每個第一級依賴項的清單文件,閱讀導入包,查看提供此類包的jar的中央倉庫,下載它們並將它們包裝成捆綁包?
注意:請提供有關如何實現此目的的詳細說明,不要只鏈接到此工具或可能解決此問題的工具。 這些工具的主要問題是缺乏示例和文檔。 例如, bundleall已被棄用,但似乎沒有工具可以替換它,至少在他們的maven bundle插件的官方文檔中,到目前為止已經棄用了...我確信我可能已經使用了能夠做的工具了這個,但缺乏文檔禁止新手用戶知道...
謝謝!
編輯-1:
謝謝你到目前為止的答案:)我認為我沒有以最恰當的方式解釋我的情況,我只是通過純文本感到有些困難。 或者也許我不理解你的答案。 我在OSGi中非常“新鮮”,我唯一的知識來自書籍(OSGi in Action等)和Google。
想象一下,我的包導入包A和B.但是包A導入包C,包B也導入包C. 但是現在C進口包裝D,E,F和G.另一方面,包裝D進口了大量其他包裝,E,F和G也是如此。
我在計算機中唯一的捆綁包是我自己的捆綁包以及提供包A和B的捆綁包,因為它們是我的第一級依賴項。 但是我沒有任何其他必需的捆綁包,即使它們作為jars安裝在我的JDK安裝文件夾中,我沒有它們作為捆綁包,甚至我也不知道在哪里可以讓罐子包裝它們(實際上我知道,但讓我想象我沒有)。
我期望構建工具做的是運行類似於以下的算法:
1)轉到我的捆綁MANIFEST.MF並閱讀Import-Package字段。 枚舉所有必需的包及其resp。 版本。
2)在Internet上的某個地方搜索我所需庫的jar或包。
3)下載每個並檢查它們是否只是普通的罐子或有一個有效的osgi清單文件(即它們是一個包)
3.1) 如果它們是捆綁包 , 則將它們復制到我的捆綁包/文件夾中。
3.2) 否則使用任何工具將jar包裝成一個包,並將包復制到我的包/文件夾中。
4)現在,對於下載/創建的每個新包重復步驟1),2),3)和4)。
我想要的最終結果是:每個庫都有一個直接或間接依賴的bundle,這樣我就可以在我的OSGi Framework實例中即時安裝它們,比如felix或equinox。
我不想要的:
1)必須手動執行此操作,因為如果我嘗試解決依賴關系的每個依賴關系,我可能花費數小時或數天收集和包裝罐子。
2)將所有依賴項嵌入到ubber / mega包中。 根據我讀過的幾本書,這是一個不好的做法,單獨維護每個依賴項更難,而且它會破壞模塊化。
注意:我的問題不是關於將jar包裝到一個包中的特定任務,而是關於遞歸地執行每個包的導入,即使它們需要從在線存儲庫(例如maven的中心)下載。
有沒有辦法自動執行此操作,或者我錯過了一些關於OSGi的大事? 如此之大,我永遠不需要這樣做,我要求的?
EDIT 2:
一些(如果不是全部)Import-Package依賴項可以在運行時解決。 想象一下OSGi框架嘗試啟動一個包,但不顯示錯誤消息“無法解析8.0:缺少需求[8.0] osgi.wiring.package;” 它會在線搜索該軟件包,下載並即時安裝。 生活會變得如此簡單。
如果你想包裝不是捆綁的jar,但只需要將這些jar作為捆綁包作為OSGi框架中的庫,你可以用BND工具包裝它。 請參閱如何從現有第三方罐創建/生成OSGi包的鏈接?
但我可以看到你使用非常常見的庫,而不是已經轉換為osgi包。 您可以在SpringSource Enterprise Bundle Repository中找到許多轉換為bundle的庫 。
但是,如果找不到任何未轉換為良好OSGi包的庫,則可以使用PAX-URL中的WRAP協議在OSGi框架中安裝這些依賴項。 要使用這些協議取決於您正在使用的OSGi框架,但是在默認情況下安裝了karaf。 例如,要從maven存儲庫安裝庫:
root@karaf> osgi:install -s 'wrap:mvn:commons-lang/commons-lang/2.4$Bundle-SymbolicName=commons-lang&Bundle-Version=2.4'
該指令將maven存儲庫中的commons-lang庫安裝到OSGi框架中,並將其包裝為OSGi包,其中標題出現在該行中。
對於自動安裝依賴性,就像你在第二次編輯中說的那樣,有幾個解決方案,但是有點工作。 自動捆綁到OSGi framewor有兩個主要的解決方案,即“Felix OBR存儲庫”和“Felix Provisioning”捆綁包以及Equinox p2存儲庫。 它們都有控制台命令來自動安裝捆綁包和功能。 問題是,實際上我找不到一個好的捆綁包公共存儲庫。 您需要使用所需的捆綁包構建自己的存儲庫。
如果使用maven-bundle-plugin,當您將工件安裝到本地maven存儲庫時,插件會更新位於存儲庫根目錄中的文件“repository.xml”,以反映捆綁包的要求和功能。 該文件是OBR存儲庫文件。
我想要的最終結果是:每個庫都有一個直接或間接依賴的bundle,這樣我就可以在我的OSGi Framework實例中即時安裝它們,比如felix或equinox。
好吧,如果我正確理解你的問題,你想要像maven-dependency-plugin這樣的東西?
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/thridparty-libs</outputDirectory>
<overWriteIfNewer>true</overWriteIfNewer>
<includeScope>runtime</includeScope>
<excludeGroupIds>${project.groupId}</excludeGroupIds>
<excludeArtifactIds>...</excludeArtifactIds>
</configuration>
</execution>
</executions>
</plugin>
如果你遇到問題,你有很多沒有osgi-Manifest的依賴項,你應該檢查它們是否在springource enterprise bundle repository http://ebr.springsource.com/repository/和apache-servicemix bundle中可用。 http://search.maven.org/#search|ga|1|g%3A%22org.apache.servicemix.bundles%22 (如我的評論中所述)
使用maven-bundle-plugin中的Conditional-Package以遞歸方式內聯JAR包中的所有必需包並激活標記true。
嘗試p2-maven-plugin它完全按照你所描述的1到4進行操作。它實際上使用tycho來構建p2存儲庫,但你也可以使用它來收集和捆綁你的依賴項和傳遞依賴項。 我不是在這里寫例子,因為在上面的鏈接中,每個思考都有很好的文檔記錄,以便於理解。
希望這可以幫助
這個函數包括jar文件夾中的jar依賴項:OSGI-INF / lib /
在build.gradle中:
**
dependencies {
...dependencies
}
def bundleClassPath() {
def list = []
configurations.compile.each {
list += 'OSGI-INF/lib/' + it.name
}
return list.join(',')
}
def includeResource() {
def list = []
configurations.compile.each {
list += 'OSGI-INF/lib/' + it.name + "=" + it.path
}
return list.join(',')
}
bundle {
instructions << [
'Bundle-ClassPath' : bundleClassPath(),
'-includeresource' : includeResource()
]
}
**
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.