OSGi模塊化框架詳解

OSGi模塊化框架是很早就出來的一個(gè)插件化框架再来,最早Eclipse用它而出名,但這些年也沒有大熱雖然OSGi已經(jīng)發(fā)布了 版本1到版本5∥偶現(xiàn)在用的最多的茵乱,也是本文講述基于的是Equinox的OSGi實(shí)現(xiàn),同時(shí)也是Eclipse核心孟岛,Spring Dynamic Module也是基于Equinox瓶竭。OSGi框架為java系統(tǒng)提供了一個(gè)通用的容器,該系統(tǒng)中的 bundle渠羞,無需停止系統(tǒng)斤贰,即可實(shí)現(xiàn) bundle 的安裝、卸載次询。OSGi是Java中目前唯一的一個(gè)模塊化荧恍、動(dòng)態(tài)化的規(guī)范。在模塊化方面OSGi聯(lián)盟已經(jīng)研究了很多年了屯吊,因此OSGi規(guī)范對于模塊的物理隔離送巡、模塊的交互、多版本這些方面都有了非常完善的機(jī)制盒卸,并且也得到了現(xiàn)在幾乎所有的App Server廠商或開源社區(qū)的認(rèn)可授艰,但至今沒有被JAVA納入語言級(有待觀察)。OSGi的突出特點(diǎn)有:

可以動(dòng)態(tài)加載世落、更新和卸載模塊而不用停止服務(wù)

實(shí)現(xiàn)系統(tǒng)的模塊化、版本化糟需,允許多版本bundule同時(shí)服務(wù)

Service model允許模塊/插件相互依賴但松耦合屉佳,分享服務(wù)更簡單

OSGi運(yùn)行在JVM之上,其架構(gòu)圖如下圖所示:

OSGi適用場景

很多人錯(cuò)誤的使用了OSGi, 套用了OSGi架構(gòu)把系統(tǒng)復(fù)雜化洲押。在我看來武花,OSGi的用處在于“模塊化”和“熱插拔”。模塊化包括模塊化杈帐、版本化和面向服務(wù)的設(shè)計(jì)体箕。熱插拔也就是說模塊/bundle的熱插拔,它可以實(shí)現(xiàn)更新和升級模塊/bundle(即系統(tǒng)的一部分)而無需重啟整個(gè)系統(tǒng)挑童。

如果你的系統(tǒng)套用了OSGi架構(gòu)累铅,bundle的相互依賴關(guān)系復(fù)雜,又沒有bundle動(dòng)態(tài)加載站叼、動(dòng)態(tài)更新娃兽、動(dòng)態(tài)卸載和動(dòng)態(tài)監(jiān)聽的機(jī)制,都是靜態(tài)啟動(dòng)所有bundle尽楔,那就是為了OSGi架構(gòu)而OSGi架構(gòu)投储,把問題復(fù)雜化了第练。其代價(jià)也是很大的,因?yàn)樵瓉砟愕膉ar包用maven來處理依賴關(guān)系和自動(dòng)更新也很方便玛荞,而由于整個(gè)系統(tǒng)建立在OSGi規(guī)范上娇掏,你的應(yīng)用所依賴的其他組件也“不得不”遷移到OSGI上來,再加上OSGI獨(dú)特的ClassLoader設(shè)計(jì)勋眯,使bundle間的類互相訪問受到一定的約束婴梧,一切都需要遷移到OSGi的約束上來。

舉個(gè)例子來說凡恍,就像Eclipse提供了動(dòng)態(tài)加載志秃、更新和刪除插件的機(jī)制,因?yàn)樗锩嬗幸粋€(gè)插件注冊和反注冊的接口和插件加載嚼酝、更新和刪除的監(jiān)聽線程浮还,這樣允許你動(dòng)態(tài)加載、更新和刪除Eclipse插件而無需重啟Eclipse闽巩。當(dāng)然钧舌,如果你當(dāng)前進(jìn)程調(diào)用了某插件,比如js語法高亮涎跨,而某插件更新了洼冻,那么當(dāng)前的js實(shí)例還是需要重新打開的。但整個(gè)Eclispe無需重啟隅很。

Java模塊化的難點(diǎn)

OSGi的一個(gè)重要特性就是模塊化撞牢,OSGi提供了一套模塊化的體系,這其中則會有明確的模塊之間接口暴露以及依賴的定義叔营,因此能夠更好的實(shí)現(xiàn)高內(nèi)聚和低耦合屋彪。那么,Java模塊化難點(diǎn)在哪绒尊?模塊的實(shí)現(xiàn)和傳統(tǒng)的編程方法確實(shí)有一些差別畜挥,主要體現(xiàn)在模塊之間類訪問的隔離、版本選擇這兩個(gè)方面婴谱。如希望更好的設(shè)計(jì)模塊化的系統(tǒng)蟹但,開發(fā)者需要掌握ClassLoader機(jī)制、模塊之間類的交互方法(這包括了模塊怎么樣對外提供可訪問的package谭羔、怎么樣訪問其他模塊提供的package华糖、如何選擇適合版本的package等)胃夏。如果不懂以上這些菊卷,貿(mào)然套用OSGi框架會誤入歧途骚腥。

重要概念:Bundle

Bundle — A bundle is a JAR file with special OSGi entries in its manifest and containing classes, resources, and other JARs登疗。Bundle谆扎,可以將其理解為自描述的 JAR 文件项郊。Bundle在OSGi中是部署的最小單位偏化,因此嗅绰,可以把它理解為模塊。在 bundle 的 manifest 文件中向族,會有對本 bundle 的標(biāo)識呵燕、提供的功能 (Export-package) 及依賴性 (Import-Package/Require-Bundle) 的定義。每個(gè) bundle 在運(yùn)行時(shí)自己的類加載器 (Class Loader)件相,這樣可以做到一方面把不同的 bundle 里面的類區(qū)別開來再扭,當(dāng) bundle 被卸載時(shí),只有這個(gè) bundle 的類加載器中的信息會丟失夜矗;另一方面泛范,可以在自己的 bundle 內(nèi)部充分利用 Java 的成員訪問控制機(jī)制。

Bundle通過MANIFEST.MF進(jìn)行自描述紊撕,下面是一個(gè)例子:

Manifest-Version: 1.0

Bundle-ManifestVersion: 2

Bundle-Name: Popup Plug-in

Bundle-SymbolicName: com.example.myosgi; singleton:=true

Bundle-Version: 1.0.0

Bundle-Activator: com.example.myosgi.Activator

Require-Bundle: org.eclipse.ui,

org.eclipse.core.runtime

Bundle-ActivationPolicy: lazy

Bundle-RequiredExecutionEnvironment: JavaSE-1.6

Bundle類隔離機(jī)制

每個(gè)Bundle均為獨(dú)立的ClassLoader罢荡,是java動(dòng)態(tài)化實(shí)現(xiàn)的基礎(chǔ)。默認(rèn)情況下有Boostrap classLoader (jre/lib/classes)对扶、Extension classloader (jre/lib/ext)区赵、 System classloader (classpath指定),應(yīng)用可以自行實(shí)現(xiàn)classloader及動(dòng)態(tài)的加載類浪南,或加載特定目錄下的類笼才。

Bundle的生命周期

Lifecycle — A lifecycle is the sequence of states a bundle goes through: uninstalled, installed, resolved, starting, stopping, active. 生命周期圖如下所示:

要注意的是:bundle狀態(tài)變?yōu)镽esolved并不表示能提供服務(wù),所以啟動(dòng)所有的bundle不表示類都已經(jīng)加載到內(nèi)存了络凿。Resolve bundle做以下的幾件事情:尋找bundle依賴的包是否存在以及被resolve骡送,尋找匹配的import package,required bundle絮记,如尋找則進(jìn)入檢查摔踱,檢查沒有沖突就形成綁定關(guān)系,以便加載類的時(shí)候能直接加載(但僅僅Resolved到千,不代表類被加載了)。在此我向大家推薦一個(gè)架構(gòu)學(xué)習(xí)交流群赴穗。交流學(xué)習(xí)群號:948368769里面會分享一些資深架構(gòu)師錄制的視頻錄像:有Spring憔四,MyBatis,Netty源碼分析般眉,高并發(fā)了赵、高性能、分布式甸赃、微服務(wù)架構(gòu)的原理柿汛,JVM性能優(yōu)化、分布式架構(gòu)等這些成為架構(gòu)師必備的知識體系。還能領(lǐng)取免費(fèi)的學(xué)習(xí)資源络断,目前受益良多如果你的BundleActivationPolicy是LAZY惰性加載裁替,bundle.loadClass()調(diào)用才會到達(dá)Active狀態(tài)。如果你的bundle的MANIFEST.MF中配置的Bundle-activator存在貌笨,那就調(diào)用其start方法弱判,從starting進(jìn)入active狀態(tài)。

osgi> ss

"Framework is launched."

id State Bundle

15STARTING com.example.serviceconsumer_1.0.0.X

16RESOLVED com.example.serviceprovider_1.0.0.X

---------------------

下面的圖更詳細(xì)的解釋了這一點(diǎn):

OSGi Service

Service — A service is an object instance exposed under the one or more interfaces that it implements and a map of properties. 簡單來說锥惋,Service model允許每個(gè)bundle對外分享一組服務(wù)昌腰,其它的bundle都可以調(diào)用這些接口的服務(wù)。這也就是OSGi bundle之間調(diào)用的方式膀跌。Service可以用來:

Export functionality from a bundle to other bundles

Import functionality from other bundles

Register listeners for events from other bundles

Expose external devices, such as UPnP devices or even hardware, to other OSGi bundles. See theDeviceandUPnPAPIs

Expose java code running in OSGI to an external network, e.g. via the UPnP orSOAPprotocols.

Bundle configuration, using theConfiguration Manager

實(shí)際做法來看遭商,通常會把接口和實(shí)現(xiàn)分開。接口放到一個(gè)bundle里面捅伤。實(shí)現(xiàn)(service)放到另外一個(gè)bundle里面劫流,類似下面的圖示中,bundle A和B是Service暑认,其interface放到Bundle C:

也可以是提供一個(gè)jar包困介,里面定義了擴(kuò)展接口,然后規(guī)定新的擴(kuò)展bundle必須實(shí)現(xiàn)該jar包里面定義的interface蘸际。實(shí)現(xiàn)示意圖如下所示(OsgiCommand接口定義在擴(kuò)展點(diǎn)jar包里面座哩,新的bundle必須包含):

Bundle的Service之間交換方式和注冊方式:

通過bundleContext.registerService注冊服務(wù),然后通過bundleContext.getServiceReference獲取服務(wù)(不推薦)

使用監(jiān)聽器listeners

ServiceListener和ServiceTracker提供bundle和service的動(dòng)態(tài)監(jiān)聽粮彤,ServiceTracker可以動(dòng)態(tài)監(jiān)聽未來的bundle和service(OSGi Release 2提供的ServiceTracker根穷,一般推薦)

通過Declarative Service(OSGiDS,或者Spring Dynamic Module(DM))的方式(OSGi Release 4開始导坟,重點(diǎn)推薦S炝肌)

第二種通過ServiceTracker來查詢或偵聽服務(wù)注冊和注銷的例子代碼:

package com.ibm.osg.example.mygetservice;

import org.osgi.framework.BundleActivator;

import org.osgi.framework.BundleContext;

import org.osgi.util.tracker.ServiceTracker;

import com.ibm.osg.example.mtservice.MyTestService;

public class MyBundleActivator

implements BundleActivator, Runnable

{

private boolean done=false;

private ServiceTracker testServiceTracker;

// Bundle Activator Start Method

public void start(BundleContext context)

{

/* Here we initialize and open our ServiceTracker.

It will track any service registering under

the "com.ibm.osg.example.mtservice.MyTestService"

interface.

*/

testServiceTracker =

new ServiceTracker(context,

"com.ibm.osg.example.mtservice.MyTestService",

null);

testServiceTracker.open();

// Here we start a thread that will continue

// to use our service until

// the bundle is stopped.

Thread t = new Thread(this);

t.setName("mygetservice thread");

t.start();

}

/*Bundle Activator Stop Method -- here we stop

the thread and close the

ServiceTracker*/

public void stop(BundleContext context)

{

done=true;

testServiceTracker.close();

}

//Here is a method that uses the service

//we are tracking. First we get

//the service

//from the tracker, then we call its printMessage

//method.

public void useService(String message){

MyTestService testService = (MyTestService)

testServiceTracker.getService();

if( testService != null )

{

// If the service is available then use it.

testService.printMessage(message);

}

else{

// If the service is not available then perform an acceptable action.

// Here we just print the message to standard out and indicate the service

// was not available.

System.out.println("No MyTestService available - " + message);

}

}

// Simply continues to use the test service

// every second until the done flag is set.

public void run(){

int i = 0;

done = false;

while (!done) {

useService("message from test " + i++);

try{

Thread.sleep(1000);

}

catch( InterruptedException ie ){

}

}

}

}

OSGi簡單起步

從Eclipse創(chuàng)建OSGi的bundle是非常簡單的

Slideshare: OSGi理論與實(shí)戰(zhàn)

OSGi動(dòng)態(tài)加載刪除bundle

使用監(jiān)聽器listeners

ServiceListener和ServiceTracker提供bundle和service的動(dòng)態(tài)監(jiān)聽,ServiceTracker可以動(dòng)態(tài)監(jiān)聽未來的bundle和service(OSGi Release 2提供的ServiceTracker惫周,一般推薦)在此我向大家推薦一個(gè)架構(gòu)學(xué)習(xí)交流群尘惧。交流學(xué)習(xí)群號:948368769里面會分享一些資深架構(gòu)師錄制的視頻錄像:有Spring,MyBatis递递,Netty源碼分析喷橙,高并發(fā)、高性能登舞、分布式贰逾、微服務(wù)架構(gòu)的原理,JVM性能優(yōu)化菠秒、分布式架構(gòu)等這些成為架構(gòu)師必備的知識體系疙剑。還能領(lǐng)取免費(fèi)的學(xué)習(xí)資源,目前受益良多

通過Declarative Service(OSGiDS,或者Spring Dynamic Module(DM))的方式(OSGi Release 4開始言缤,重點(diǎn)推薦=朗础)

具體實(shí)現(xiàn):

對于DS,<Define a declarative OSGi Service>, <IBM: Declaring your services to OSGi Declarative Services>轧简,<java OSGI Declarative Services Component bundles Example>驰坊。

對于Spring DM,<OSGI and Spring Dynamic Modules – Simple Hello World>, <Hello, OSGi, Part 2: Introduction to Spring Dynamic Modules>

分布式OSGi(Distributed OSGi)

OSGi容器可以包含幾千個(gè)bundlue沒有問題哮独,但如何應(yīng)對幾十萬個(gè)的情況拳芙?如何像EJB3一樣具有分布式部署和便攜性呢?有一個(gè)OSGi的子項(xiàng)目:分布式OSGi(Distributed OSGi)皮璧。

上圖是一個(gè)demo演示舟扎,兩個(gè)分布式OSGi Container,都部署了Greeter接口bundle悴务,都基于分布式OSGi實(shí)現(xiàn)睹限,能實(shí)現(xiàn)分布式調(diào)用OSGi Service。分布式OSGi(Distributed OSGi)還可以與RESTful Service (JAX-RS / JSR-339)整合讯檐。分布式OSGi有幾十萬個(gè)bundle怎么管理羡疗,這是個(gè)麻煩,而且如何啟動(dòng)停止别洪,啟動(dòng)順序怎么樣叨恨?可管理性是個(gè)麻煩,ACE項(xiàng)目試圖解決這個(gè)事情挖垛。

DOSGi的原理(由Distribution provider來給OSGi Service創(chuàng)建Endpoint痒钝,使這些Service在OSGi Container外部可訪問,另外一端則創(chuàng)建代理痢毒;此外送矩,有監(jiān)聽器來偵聽OSGi Service的創(chuàng)建和啟停等):

分布式OSGi與ZooKeeper

ZooKeeper是Hadoop的一個(gè)子項(xiàng)目,它是一個(gè)針對大型分布式系統(tǒng)的可靠協(xié)調(diào)系統(tǒng)哪替,提供的功能包括:配置維護(hù)栋荸、名字服務(wù)、分布式同步凭舶、組服務(wù)等晌块。ZooKeeper的目標(biāo)就是封裝好復(fù)雜易出錯(cuò)的關(guān)鍵服務(wù),將簡單易用的接口和性能高效库快、功能穩(wěn)定的系統(tǒng)提供給用戶摸袁。

分布式OSGi(Distributed OSGi)在Discovery這一塊使用了ZooKeeper钥顽。所謂Discovery模塊就是用來發(fā)現(xiàn)和偵聽分布式的遠(yuǎn)端的可用的Endpoints义屏。Discovery Ditributed with Zookeeper的架構(gòu)圖:

參考:DOSGi使用ZooKeeper server的安裝和Demo

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子闽铐,更是在濱河造成了極大的恐慌蝶怔,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兄墅,死亡現(xiàn)場離奇詭異踢星,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)隙咸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進(jìn)店門沐悦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人五督,你說我怎么就攤上這事藏否。” “怎么了充包?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵副签,是天一觀的道長。 經(jīng)常有香客問我基矮,道長淆储,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任家浇,我火速辦了婚禮本砰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蓝谨。我一直安慰自己灌具,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布譬巫。 她就那樣靜靜地躺著咖楣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪芦昔。 梳的紋絲不亂的頭發(fā)上诱贿,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天,我揣著相機(jī)與錄音咕缎,去河邊找鬼珠十。 笑死,一個(gè)胖子當(dāng)著我的面吹牛凭豪,可吹牛的內(nèi)容都是我干的焙蹭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼嫂伞,長吁一口氣:“原來是場噩夢啊……” “哼孔厉!你這毒婦竟也來了拯钻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤撰豺,失蹤者是張志新(化名)和其女友劉穎粪般,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體污桦,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡亩歹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了凡橱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片小作。...
    茶點(diǎn)故事閱讀 40,498評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖稼钩,靈堂內(nèi)的尸體忽然破棺而出躲惰,到底是詐尸還是另有隱情,我是刑警寧澤变抽,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布础拨,位于F島的核電站,受9級特大地震影響绍载,放射性物質(zhì)發(fā)生泄漏诡宗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一击儡、第九天 我趴在偏房一處隱蔽的房頂上張望塔沃。 院中可真熱鬧,春花似錦阳谍、人聲如沸蛀柴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鸽疾。三九已至,卻和暖如春训貌,著一層夾襖步出監(jiān)牢的瞬間制肮,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工递沪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留豺鼻,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓款慨,卻偏偏與公主長得像儒飒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子檩奠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容