之前的Opendoc中沒有涉及過此部分的內容,maven又是現在非常流行的java的工具,再加上到目前為止搭建OSGi Maven開發和部署的環境還是比較的麻煩,覺得有必要寫篇這樣的blog,:),在這篇blog中來看下如何搭建一個比較好用的OSGi Maven開發和部署環境,看看我在搭建一個這樣的環境中的痛苦歷程。
首先說下我期望的OSGi Maven開發/部署的環境:
1、META-INF中的manifest.mf文件可以自己控制;
Eclipse對插件工程的開發支持的很好了,在IDE中可以很方便的去修改這個manifest.mf,所以還是自己控制更爽,當然,打包的時候需要打入自己控制的這個manifest.mf。
2、在mvn eclipse:eclipse生成的.classpath中,能夠不把所依賴的bundle的jar包放進去;
因為在OSGi環境中,已經不再通過直接在project的classpath中依賴其他bundle的jar了來調用其他bundle中的package,而是通過在manifest.mf中增加import-package這樣的方式,所以不能再把依賴的bundle的jar打到classpath里了,否則會很奇怪,當然,這也源于eclipse有個很好的插件開發環境,讓你可以在不依賴bundle jar的情況下直接寫依賴其他bundle的package的代碼。
3、在mvn clean package的時候能夠把需要依賴的jar打到bundle jar中,并和META-INF/Manifest.mf文件中的Bundle-Classpath是匹配的;
在某些bundle中可能會依賴一些jar,在META-INF中通常會去指定依賴的這些jar,放入bundle-classpath中,因此要求在打包的時候能夠把這些依賴的jar打入相應的路徑下。
說完想法后,首先想到的是在OSGi界中支持maven環境的大名鼎鼎的maven-bundle-plugin(
http://felix.apache.org/site/apache-felix-maven-bundle-plugin-bnd.html),maven-bundle-plugin基于Peter寫的bnd實現,不說廢話了,按照自己期望的環境來使用maven-bundle-plugin進行搭建:
步驟一
按照上面頁面的指導,在pom.xml中增加maven-bundle-plugin先,接著按照自己的想法,要自己控制manifest.mf,于是在plugin的configuration中增加:
<_include>META-INF/MANIFEST.MF</_include>
滿心歡喜的等待著完美的結果,可惜....不如人意呀,打包出來的jar里面的MANIFEST.MF已經物是人非了,完全不是自己控制的那個,插件給你自動的加上了一堆的import-package、private-package、export-package,我知道這個插件是基于bnd來寫的,但沒想到竟然連自己控制的權力都不給我了,完全仍然是通過bnd來計算出import-package、private-package什么的;
步驟二
好,在傷心過后接著仔細看,還好,在plugin的configuration中可以自己指定export-package、private-package這些,于是繼續欣喜的使用,這兩個倒是控制住了,但....import-package自己是不能控制的,這個是不行的,這樣就導致了必須同時自己維護pom.xml以及project中的META-INF/MANIFEST.MF,讓它們保持一致,否則可能導致打出來的包和你在project中運行的表現不一致,并且bnd計算出來的import-package并不是我想要的,有點太復雜了,還是自己控制比較好;
步驟三
傷心到極點了,其實到目前為止,已經可以確定maven-bundle-plugin,也是OSGi maven中唯一的插件,不能滿足我的需求,不過還是繼續看看這個插件其他方面的表現,驚喜的發現有一點倒是做的不錯的,它支持一個
<Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>,有了這個標簽后,它可以直接把依賴的jar打入bundle jar包中,并且相應的自動在bundle-classpath中加上了,這點倒是不錯的,看起來與我期望的環境的第3點是比較匹配的,可惜了。
還有就是,很當然的,它沒法做到控制mvn eclipse:eclipse時生成的.classpath不包含bundle jar的引用。
按照上面的三個步驟,總結下,有些時候智能是好事,但maven-bundle-plugin就是過于智能了,為什么不給點權力給使用者呢,因此這個插件要提升到完全可用的情況的話,還需要提供下讓使用者自己控制MANIFEST.MF的權力,相信這點要做到并不困難,而且做到這點后基本也就可以使用了。
繼續尋找,于是靜心分析了下自己的需求,貌似可以自己通過maven現有的幾個插件來達成自己的愿望,于是開始了組合拳:
1、MANIFEST.MF文件自己控制
不就是要自己控制這個文件嘛,OK,干脆,就只用maven-jar-plugin,這個插件允許指定所使用的MANIFEST.MF文件,于是,嘗試著在這個plugin的configuration中增加:
<archive>
<manifestFile>META-INF/MANIFEST.MF</manifestFile>
</archive>
恩,很順利,開門紅呀,打出來的jar包中的MANIFEST.MF文件就是自己的那個。
2、mvn eclipse:eclipse生成的.classpath中要去掉bundle jar的依賴
對于我這么一個對maven不是那么熟悉的人來講,這個有點復雜,于是不斷的google,甚至是翻看了maven-eclipse-plugin的源碼...
最終終于功夫不負有心人,找到一個簡單的辦法:
首先將工程方式指定為pde,也就是eclipse插件工程,在maven-eclipse-plugin的configuration配置中增加<pde>true</pde>;
然后在pom.xml中將不希望生成到.classpath中依賴的scope指定為provided;
心驚膽戰的開始運行mvn eclipse:eclipse,OH YEAH!,成功!
ps: 另外也可以通過在maven-eclipse-plugin的configuration中增加exclude配置,來將某些依賴從.classpath中去掉,當然,這方法沒有上面的易用。
3、在mvn clean package的時候能夠把需要依賴的jar打到bundle jar中,并和META-INF/Manifest.mf文件中的Bundle-Classpath是匹配的;
恩,這點,印象中貌似maven是有支持的,于是繼續開始找,終于找到了maven-dependency-plugin(之前還找到了一個maven-shade-plugin,也很帥,不過不滿足需求),通過這個插件可以把需要的依賴的jar都復制到某個指定的目錄中去,但記得把這個指定的目錄加入到maven-jar-plugin的resources目錄里面去,否則這些jar文件是不會出現在你的bundle jar里的。
OK,通過上面這套組合拳,終于達成了目的,看來有必要找個時間寫個好用點的maven的OSGi插件,否則真的忒折騰了,上面這個方法仍然有幾個痛苦的地方:
1、如果你的bundle中需要export其中依賴的lib的package的話;
mvn eclipse:eclipse之后你會發現其他bundle即使import了這個package,也會調用不到,這里的原因在于生成的.classpath中所依賴的那個lib的exported屬性沒有設置為true,google了maven eclipse插件,貌似這是它的一個缺失的功能,因此在目前只能是mvn eclipse:eclipse后,再到build path里把這些lib exported出去。
2、還是得在插件的pom.xml中配置所依賴的其他的bundle;
這是為了讓你在mvn clean package的時候能通過,這點還是挺郁悶的,如果能自己去找到的話就好了(Felix構建bundle repo是有潛質做到這點的),:),這樣導致了在每次在import package后,還得記得去修改了pom,否則的話在eclipse compile什么都正常,到了maven里就掛了。
因此,如果能解決上面兩點的話,那將更加完美。