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