走近Java模块化系统OSGi
OSGI是什么?
剛入軟件開發行業的初哥可能會覺得到處都是值得頂禮膜拜的大神,到處都是復雜到自已無法把握的代碼,驚嘆這些大神怎樣能寫出如此神奇的程序出來?!
其實真正好的軟件的代碼,應該是結構清晰,簡單易懂的代碼(別提linux內核代碼,那是另類)。
說到底,軟件設計就不外乎復用、內聚、藕合三個主題。
OSGI作為Java的模塊化規范,也是為了更好地解決java在這三個主題的問題。
要理解OSGI,首先要知道OSGI不是一個應用層面的框架,而是設計層面的規范,所以不要用理解spring、hibernate、structs那樣的框架的方式來理解OSGI,如果一定要找一個類似的東西和OSGI對比的話,我想會是OO(Object-Orient面向對象)。所以,不要問“怎么將spring和OSGI集成?”這樣的問題,被象你不會問“怎么將spring和OO集成?”一樣。
其次,OSGI的目的是模塊化,就是為了將一個大的應用分解成較小的模塊,這些模塊物理上就是一個個的jar包,也就是OSGI bundle。OSGI規范就是指導怎么令這些bundle能更好的有高內聚性、有松藕性,能更好地被復用。至于被神化的“動態性”、“熱插拔”的特性,則是OSGI規范帶來的一種可能,并不是一定會有的。這些特性是需要配合好的設計才能達到。
最后,OSGI的課程不是去教你學會一種開發語言,也不是去教你學用一套應用框架,而是教你去設計你的應用,是一種形而上的課程,需要個人去領悟。
OSGI framework和bundle的生命周期
OSGI規范定義了一個叫OSGI framework的平臺,這個平臺是一個運行在JVM上的應用。它負責管理我們上節提到的bundle(也就是一個符合OSGI規范的Jar包)。
對于bundle,我們需要關注它的生命周期。
首先,bundle需要install到osgi framework上,這個install只是讓framework用一個classloader來裝載bundle里的類和資源。
接著就是resolve,檢查bundle需要“引用”的package是否可用,這個后續再詳細介紹。
然后,bundle就要start,也就是運行activator里的start方法,方法運行完畢,即進入"ACTIVE"的狀態,這時bundle就算正式可用了。
bundle的隔離
“模塊化”的模塊是一些相對獨立的實體,它們是有邊界的,就好象我們在OO里看到,類也是有邊界的,它一般是以一個類文件作為邊界,而OSGI模塊的邊界則是一個Jar包,也就是一個bundle。簡單的說:在OSGI范疇內,模塊就是一個bundle,一個bundle就是一個模塊。
在傳統的java應用開發中,我們很少去關注jar包的隔離性,通常只需要知道我們的應用都用到哪些jar包,在部署時,將這些jar包一起部署,就可以用jar包里的java類了。也就是說,在運行時,一堆的jar包并不需要我們去特意去分辨它們之間的關系,部署好后,該用到誰就自然能用上誰,整個應用就是一體的,jar包的依賴關系并不清晰。
而在OSGI規范下,bundle是被“有計劃地”依賴著,你得顯式地說明模塊之間的依賴關系。OSGI是利用JVM的classloader和它的父委托模型(PDM:Parent Delegation Mode)來實現這點的。
故名思義,classloader就是加載java類的加載器,一個classloader加載的類,就只能被這個classloader及其子classloader加載的其它類訪問到。也就是說,如果兩個不是父子關系的classloader加載的類是互相不可見的。
而OSGI對每一個bundle都分別用一個classloader來加載里面的類,所以不同bundle之間的類,在默認情況下,是互不可見的。
如果沒有額外處理,一個bundle里的類要訪問另一個bundle里的類時,通常會出現ClassNotFound的異常,可以說這個異常將是OSGI初學者最常見到的異常。
bundle之間的藕合
一般來說,單個的bundle并不是完整的應用,它需要和其它bundle組合在一起才能真正發揮作用。
在上面,我們提到由于每個bundle的classloader都不同,所以它們的類是互不可見的。
為了能引用別的bundle的類,osgi通過import/export package的機制來控制bundle間有限地藕合。
在bundle的設計時,我們將需要給其它bundle“訪問”的類放在若干個package內,然后export這些package,就可以讓其它bundle通過import package的方式“訪問”到這些package里的類,而沒被Export的package里的類則被“保護”起來。
注意:Export/Import package是通過bundle里的META-INF/manifest.mf文件里指定的。
更松散的藕合-osgi service
除了通過import/export package的機制實現bundle間的藕合,我們還可以通過osgi service的方式實現藕合。osgi service是osgi規范中定義的一種本地服務的機制,“本地”意味著它只是在osgi framework內有效,不可跨osgi framework調用,更不可跨JVM調用。osgi service可以認為是一種“微服務”,可以在bundle之間引用。
osgi framework有一個service registry,bundle可以把一個實現某種接口的bean實例作為osgi service注冊(register)到service registry上,其它bundle就可以從service registry上發現并引用它,所以,本質上osgi service就是一個bean。
通常,我們會把接口定義在一個bundle A里,接口的實現則在另一個bundle B里,并將接口實現實例化后注冊成osgi service,而第三個bundle C則引用這個osgi service。
因為bundle B和C都需要用到bundle A的接口定義,所以bundle A需export接口定義所在的package,而bundle B和C則需import這個package。這樣bundle B和C之間就不需用export/import package來藕合了,實現B和C之間的解藕。
在osgi的應用中,會有大量的osgi service存在,可以說osgi service是osgi規范中最重要的機制,沒有之一。
其它機制
OSGI規范還提供了Event、配置管理(ConfigAdmin)、聲明式服務(Delarative Service)、Service Tracker、Blueprint等等運行時機制,方便我們構建模塊化的應用系統,這些機制,以后再介紹。
版權聲明
本文由killko創作,轉載需署名作者且注明文章出處
參考代碼
要獲取本文的參考代碼,請訪問:?https://www.tianmaying.com/tutorial/osgi-kickstart/repo
from:https://www.tianmaying.com/tutorial/osgi-kickstart?
總結
以上是生活随笔為你收集整理的走近Java模块化系统OSGi的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java模块化之路 —— OSGI介绍
- 下一篇: OSGI动态加载删除Service bu