Equinox動態(tài)化深入分析

             OSGi最吸引人的特性除了模塊化之外,就是動態(tài)化了,在我之前寫的OSGi實(shí)戰(zhàn)以及進(jìn)階兩篇Opendoc中,都有相關(guān)的示例,但不知道大家有沒有注意,在兩篇Opendoc中都未提及到bundle本身的更新,而基本都是以新增服務(wù)實(shí)現(xiàn)的bundle以及停止服務(wù)時(shí)限的bundle為例,并且相對而言是個(gè)比較簡單的例子,動態(tài)化在java界更明確的詞也許是hot deployment,而hot deployment的實(shí)現(xiàn)并不容易,同樣,即使你采用OSGi,但也不代表你的應(yīng)用就具備了hot deployment的能力,在hot deployment上,完美的結(jié)果就是當(dāng)更新完成后,新的執(zhí)行請求就在新的代碼邏輯上正確的執(zhí)行,就像沒發(fā)生過更新這回事樣,但實(shí)際要做到這樣的效果,遠(yuǎn)沒這么容易,即使是基于OSGi也同樣如此,No magic & no silver bullet,在本篇blog中我們就來具體的看看。

              OSGiBundle為粒度來實(shí)現(xiàn)動態(tài)化,也就是說,如果要更新一個(gè)類,需要做的是更新整個(gè)Bundle,雖然比直接部署一個(gè)類麻煩了點(diǎn),但也還算是不錯(cuò)的了,更新的方法有兩種,一種是直接updatebundle(在MANIFEST.MF中增加Bundle-UpdateLocation來指定Bundle更新時(shí)所使用的文件);另外一種是先uninstall舊的bundle,然后再安裝并啟動新的bundle,無論是哪種方法,對于OSGi的應(yīng)用而言,問題就在于package的類的改變以及bundleOSGi服務(wù)實(shí)現(xiàn)的改變。

              Equinox中,當(dāng)update一個(gè)Bundle時(shí),如果這個(gè)Bundle中有對外暴露的package,如果這個(gè)Bundlesingleton模式,在update后仍然保留了同樣的Bundle SymbolicName的話,其實(shí)是無法update成功的,會報(bào)出一個(gè)已經(jīng)有相同的SingletonBundle存在,因此update這種方法僅適用于沒有對外暴露packagebundle,如bundle沒有對外暴露的packageEquinox則可正常的完成update過程,通常來講,不對外暴露packagebundle都是一些對外暴露OSGi服務(wù)或者使用OSGi服務(wù)的類,對于對于暴露OSGi服務(wù)的類而言,在update過程中將會把依賴了此OSGi服務(wù)的OSGi組件的實(shí)例銷毀(遞歸),等當(dāng)前bundle更新并啟動完畢后,會重新實(shí)例化該OSGi組件,同時(shí)將新的服務(wù)實(shí)現(xiàn)對象設(shè)置進(jìn)去,對于僅使用其他Bundle提供的OSGi服務(wù)的類而言則很簡單了,在啟動此bundle時(shí)自然會設(shè)置進(jìn)來,同時(shí)也不會影響外部bundle

              從上可見,通過update方式來完成Bundle的更新受到了很大的限制,畢竟大部分時(shí)候Bundle都是singleton的,并且在更新的時(shí)候也是不會去改變其Bundle SymbolicName

              因此,在Equinox中要實(shí)現(xiàn)Bundle的更新,通常都使用另外一種方法,就是uninstall,然后再installstart更新后的bundle

              當(dāng)uninstall時(shí),如果此bundle有對外暴露的package,并且有使用這些packagebundle,那么Equinox會保留此Bundleclassloader,也就是說原來使用了這些packagebundle仍將使用之前bundle的類,這也是為什么一個(gè)Bundle uninstall了之后,其他Bundle仍然可使用該Bundleexport的類,要想讓Bundle對外exportpackage的引用也失效并且切換到新的bundleexportpackage,必須執(zhí)行refresh動作,refresh時(shí)equinox將會找到之前uninstall沒完全成功的bundle,并遞歸找到使用了這個(gè)bundlepackagebundle,將這些bundle的狀態(tài)也置為unresolve,并解除對之前uninstall沒完全成功的bundleclassloader的引用,這樣被uninstallbundleclass就能被GC卸載了,在此之后,Equinox會嘗試再次去resolve之前設(shè)置為unresolvebundle,如果resolve不了則會調(diào)用這些bundlestop方法,卸載其對外提供的OSGi服務(wù)以及引用的OSGi服務(wù),同時(shí)將其狀態(tài)置為INSTALLED;但在uninstall時(shí),對OSGi服務(wù)的處理方法則不太一樣,此Bundle中所引用的OSGi服務(wù)會被釋放,對外提供的OSGi服務(wù)也會注銷,這會造成引用了這些OSGi服務(wù)的BundleOSGi組件(遞歸)的實(shí)例會被銷毀。

              完成了以上的動作后,可以安裝新的bundle,安裝新bundle時(shí),其實(shí)就是做了些解析bundle的事情,直到start bundle時(shí),才開始resolve過程,所謂resolve就是找到bundle對外提供的package、需要引用的package等,同時(shí)創(chuàng)建bundleclassloader,在這個(gè)過程,equinox也會對系統(tǒng)中所有unresolvedbundle進(jìn)行resolve,如能夠resolve則將其狀態(tài)轉(zhuǎn)化為resolved,最后調(diào)用BundleContextstart來完成bundle的啟動,這個(gè)過程僅僅是在配置了BundleActivator的情況下才有意義,DS則完成此bundle中引用的OSGi服務(wù)或?qū)ν馓峁?/span>OSGi服務(wù)的組件的條件的檢測,以判斷這些組件是否可實(shí)例化,如有新的OSGi服務(wù)可對外提供,那么DS會檢測此時(shí)其他Bundle中的OSGi組件是否需要被激活,或者是否需要調(diào)用其他BundleOSGi組件的set方法。

              根據(jù)以上這樣的描述,可以看出,在OSGi中如果要更新沒有對外提供packageBundle是比較容易的,update以及uninstallàstart都是可選的方法,而對于對外提供了packageBundle而言,則相對復(fù)雜很多,只能選擇uninstallàrefreshàstart來完成。

              從兩個(gè)緯度來看OSGi的動態(tài)化,對于有export-package Bundle的更新,OSGi將會重建更新的bundle以及引用了此bundlepackageClassLoader,而對于OSGi服務(wù)組件的更新,OSGi則會重新創(chuàng)建引用了此OSGi服務(wù)的組件的實(shí)例,并通過unset這樣的方法通知原來的組件釋放對OSGi服務(wù)的引用,同時(shí)通過set方法來給新創(chuàng)建的實(shí)例注入更新后的OSGi服務(wù)組件實(shí)例,其實(shí)這也是hot deployment中常見的對于引用變更的處理方法。

              但從上面也可以看出,OSGi并沒有提供對象狀態(tài)保留的處理,這也就意味著,基本上在一次更新后,此次更新的Bundle以及相關(guān)的bundle因?yàn)?/span>classloader的重建,其對象的狀態(tài)數(shù)據(jù)都丟失了,不過對于更新的僅為提供或引用OSGi服務(wù)的Bundle而言,則稍微好點(diǎn),畢竟只是影響到了遞歸的引用了OSGi服務(wù)的組件,組件由于重建實(shí)例,而導(dǎo)致狀態(tài)數(shù)據(jù)丟失,這個(gè)倒是可以通過將服務(wù)的引用數(shù)量設(shè)置為cardinality=”0..1”cardinality=”0..n”來解決,設(shè)置成這樣的條件后,即使引用了需要更新的Bundle中提供的OSGi服務(wù),其OSGi服務(wù)組件實(shí)例也不會被重建,這對于需要將OSGi服務(wù)引用提供給外部使用的系統(tǒng)而言,無疑非常有幫助。

              根據(jù)以上所述,可以看到,即使是基于OSGi,要實(shí)現(xiàn)hot deployment還是比較麻煩的,No magic and no silver bulletJ,尤其是要注意classloader的重建以及OSGi服務(wù)組件實(shí)例的重建,否則很有可能會造成在更新后系統(tǒng)的異常,在基于OSGi實(shí)現(xiàn)hot deployment時(shí),要合理的規(guī)劃系統(tǒng),常見的一些較好的實(shí)踐方法有:

          l  接口和實(shí)現(xiàn)分離

          避免因?yàn)閷?shí)現(xiàn)邏輯要更新,而造成其他引用了此Bundle export出去接口所在的package而導(dǎo)致classloader的重建。

          l  對于需要保留狀態(tài)數(shù)據(jù)的OSGi服務(wù)盡量避免引用其他bundle export-package中的類

          這也是為了避免這些類所在的bundleclassloader重建,畢竟OSGi服務(wù)組件類可以通過設(shè)置cardinality來保持組件實(shí)例的不變。

          l  服務(wù)組件采用cardinality=”0..1”cardinality=”0..n”來設(shè)置對OSGi服務(wù)的引用

          避免服務(wù)組件實(shí)例的重建,畢竟這是個(gè)遞歸過程,影響還是很大的,而且誰也不敢肯定這么多的服務(wù)組件實(shí)例的重建是不是會造成系統(tǒng)的異常現(xiàn)象。

          在這種情況下,尤其要注意unset中的處理以及當(dāng)沒有可用服務(wù)情況下的處理,避免出現(xiàn)NPE

          l  盡量采用OSGi服務(wù)組件服務(wù)方式,而不是直接的類方式

          由于類方式的更新成本實(shí)在是比較的高,畢竟那需要classloader的重建,但是有些類確實(shí)是沒辦法的,對于這些類要盡量的保證穩(wěn)態(tài)。

          l  嚴(yán)格的版本控制

          畢竟接口的更新影響是很大的,因?yàn)樗袑?shí)現(xiàn)接口的類都得改變,因此需要嚴(yán)格的制定版本規(guī)范,并在引用package時(shí)按照版本規(guī)范指定相應(yīng)的版本范圍。

           

          廣告時(shí)間:在我和一位同事的新書《OSGi原理與最佳實(shí)踐》中會更加詳細(xì)的分析equinoxfelixOSGi框架在模塊化、動態(tài)化方面的實(shí)現(xiàn)方法,并會給大家推薦一些比較好的實(shí)踐。

          posted on 2009-04-29 21:00 BlueDavy 閱讀(7091) 評論(10)  編輯  收藏 所屬分類: OSGi、SOA、SCA

          評論

          # re: OSGi動態(tài)化深入分析 2009-04-30 15:46 Hugo

          如果按先Install新的,start后再Uinstall老的會不會有問題?  回復(fù)  更多評論   

          # re: OSGi動態(tài)化深入分析 2009-04-30 15:49 BlueDavy

          @Hugo
          start不了新的,詳細(xì)原因在文中已經(jīng)講了。  回復(fù)  更多評論   

          # re: OSGi動態(tài)化深入分析 2009-04-30 16:37 Hugo

          我用Felix可以同時(shí)start兩個(gè)相同的SymbolicName的Bundle,只要Bundle-Version不同就可以了。  回復(fù)  更多評論   

          # re: OSGi動態(tài)化深入分析 2009-04-30 17:12 cROSSaGE

          新書合時(shí)會出?
          很感興趣,必買.  回復(fù)  更多評論   

          # re: OSGi動態(tài)化深入分析 2009-04-30 17:49 BlueDavy

          @Hugo
          恩,那看來felix這點(diǎn)的實(shí)現(xiàn)上比equinox好,我這篇blog是針對equinox說的,不過理論上來講,同時(shí)啟動兩個(gè)同樣symblicName的singleton的bundle是有點(diǎn)問題的。  回復(fù)  更多評論   

          # re: OSGi動態(tài)化深入分析 2009-04-30 20:51 YuLimin

          在install & uninstall這空中的縫隙時(shí)間內(nèi)的業(yè)務(wù)處理是根據(jù)什么樣的策略來實(shí)現(xiàn)的?是直接拋錯(cuò)?還是等待?還是。。。?  回復(fù)  更多評論   

          # re: OSGi動態(tài)化深入分析 2009-05-01 08:40 yuping322@gmail.com

          所有的替換都強(qiáng)制規(guī)定以bundle為最小單位,要替換時(shí),先加實(shí)現(xiàn)接口的新的bundle進(jìn)去,啟動該bundle,該接口實(shí)現(xiàn)的類有兩個(gè),停止原來的那個(gè),新的自然會補(bǔ)充上。

          這樣行不?  回復(fù)  更多評論   

          # re: OSGi動態(tài)化深入分析 2009-05-01 14:05 BlueDavy

          @YuLimin
          在升級的過程中只能是拋錯(cuò)了。

          @yuping322@gmail.com
          已經(jīng)說過了,如果是bundle是singleton的話,在equinox中是沒法在不uninstall之前的bundle情況下安裝的,不過據(jù)之前hugo的說法,在felix中應(yīng)該可以。
            回復(fù)  更多評論   

          # re: Equinox動態(tài)化深入分析 2009-06-08 15:44 luguo

          《OSGi原理與最佳實(shí)踐》啥時(shí)候出版?  回復(fù)  更多評論   

          # re: Equinox動態(tài)化深入分析 2009-06-08 16:55 BlueDavy

          @luguo
          預(yù)計(jì)在9月中下旬上市。  回復(fù)  更多評論   

          公告

           









          feedsky
          抓蝦
          google reader
          鮮果

          導(dǎo)航

          <2009年4月>
          2930311234
          567891011
          12131415161718
          19202122232425
          262728293012
          3456789

          統(tǒng)計(jì)

          隨筆分類

          隨筆檔案

          文章檔案

          Blogger's

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 中卫市| 汉中市| 长顺县| 铅山县| 兴国县| 平凉市| 平乐县| 武安市| 进贤县| 阳曲县| 新余市| 嘉黎县| 昌江| 哈密市| 成都市| 芷江| 饶河县| 保定市| 博爱县| 蓬溪县| 岐山县| 芦山县| 什邡市| 宁海县| 浦江县| 盐山县| 临桂县| 青冈县| 贺兰县| 美姑县| 河曲县| 兰考县| 蛟河市| 西峡县| 桃园市| 唐海县| 上杭县| 平原县| 邛崃市| 沐川县| 桂平市|