Java 9,OSGi和模塊化的未來(2)[翻譯]

Java 9 中一個重要的新特性就是模塊化灿意。它的實現(xiàn)機(jī)制是什么那估灿?它和已有的模塊框架OSGi有什么差異那壤短?為了回答這些問題祷膳,本人在網(wǎng)上找到了一篇比較好的介紹文章,為了加深理解以政,對文章進(jìn)行了翻譯鞭执。由于原文分為2個部分司顿,所以翻譯對應(yīng)也分為2篇:

1)《Java 9,OSGi和模塊化的未來(1)》是對《Java 9, OSGi and the Future of Modularity (Part 1)》的翻譯兄纺,文章日期為2016年9月22日大溜。介紹的內(nèi)容包括:背景、高層次比較估脆、復(fù)雜性钦奋、依賴粒度對比、模塊導(dǎo)出對比疙赠、模塊導(dǎo)入對比付材、反射和服務(wù)。

2)《Java 9圃阳,OSGi和模塊化的未來(2)》是對《Java 9, OSGi and the Future of Modularity (Part 2)》的翻譯厌衔,文章日期為2016年10月4日。介紹的內(nèi)容包括:動態(tài)性捍岳、二者協(xié)同工作富寿、未來發(fā)展、結(jié)論锣夹。

本文是對原文第二部分的翻譯页徐。

引言

關(guān)鍵點

  • Java 9 在2017年發(fā)布,其中一個重要的特性就是新的模塊化系統(tǒng)银萍,被稱作Java平臺模塊系統(tǒng)(Java Platform Module System变勇,JPMS)。本文將介紹它與Java已有的模塊標(biāo)準(zhǔn)化機(jī)制OSGi的關(guān)系贴唇,以及對OSGi的影響搀绣。
  • 自1.0版本以來Java平臺已經(jīng)增長了20倍飞袋,整個平臺存在著模塊化的需求。為了解決這個問題豌熄,進(jìn)行了很多不成功的嘗試授嘀。與之相對的是,OSGi已經(jīng)提供了16年的應(yīng)用模塊化服務(wù)锣险。
  • OSGi和JPMS在實現(xiàn)細(xì)節(jié)上差別很大蹄皱。如果將JPMS作為模塊化的一般解決方案,會存在一些重大的缺陷芯肤,并且缺少OSGi的一些特性巷折。
  • JMPS的目標(biāo)是比OSGi更簡單和更容易,但是對一個非模塊化的產(chǎn)品進(jìn)行模塊化設(shè)計本身就是一件很復(fù)雜的事情崖咨,JMPS看起來好像還沒有實現(xiàn)這個目標(biāo)锻拘。
  • JMPS在對Java平臺本身的模塊化方面做得非常好,這意味著我們可以在運行時只加載和任務(wù)相關(guān)的Java平臺組件击蹲。對于應(yīng)用模塊化署拟,OSGi有很多的優(yōu)點。我們已經(jīng)證明這兩者可以很好地結(jié)合在一起歌豺。

這篇文章是“Java 9, OSGi and the Future of Modularity”文章系列的第二部分推穷。第一部分請查看《Java 9, OSGi and the Future of Modularity (Part 1)》

本文將繼續(xù)深入了解OSGi和JPMS(Java Platform Module System)类咧,其中JPMS會作為Java 9的一個組成部分馒铃。在上篇文章中,我們在一個較高的層次比較了這兩個模塊化系統(tǒng)痕惋,討論了它們是如何解決模塊間的隔離性的区宇。我們研究了依賴關(guān)系是如何建立的,并且我們探討了一些關(guān)于反射的問題值戳。本文作為第二個部分议谷,將探討版本管理、模塊動態(tài)加載以及二者潛在的協(xié)同工作可能性述寡。

版本管理

版本管理是所有軟件交付的一個關(guān)鍵點柿隙。API和實現(xiàn)都會改變,所以無論何時我們依賴它們鲫凶,我們都隱含地依賴于它們在某個時間點的存在。任何模塊系統(tǒng)必須能夠處理這個現(xiàn)實衩辟,通常用顯式的版本來指明依賴關(guān)系螟炫。

然而并非所有的改變都具有同樣的破壞性。如果我們使用了版本為1.0.0的模塊的來構(gòu)建和測試我們的軟件艺晴,那么當(dāng)我們部署版本1.0.1或1.0.5時昼钻,我們有可能可以繼續(xù)工作掸屡,但是如果部署的是版本2.0.0或版本5.2.10,那么不能工作的可能性較大然评。這表明模塊系統(tǒng)需要了解并支持兼容性范圍仅财。

OSGi一直支持這些概念。Bundle在導(dǎo)出包時標(biāo)注了版本號碗淌。在導(dǎo)入包的時候指明了版本范圍盏求,通常使用閉開區(qū)間來表示這個范圍,例如“[1.0.0, 2.0.0)” 表示版本介于1.0.0和2.0.0之間亿眠,不包括2.0.0碎罚。OSGi使用語義版本控制,與流行的語義版本規(guī)范完全一致(盡管OSGi早于那些規(guī)范)纳像。大致來說荆烈,版本號的第一段是主版本號,表示功能和API的重大變化竟趾,第二段是次版本號憔购,表示功能的增強(qiáng),第三段表示增加了一些補(bǔ)丁岔帽。

OSGi的開發(fā)者不需要推理或顯式地聲明這些版本范圍玫鸟。和 import 一樣,版本范圍可以在構(gòu)建時期根據(jù)依賴情況自動構(gòu)建山卦。例如鞋邑,如果我們僅需要使用一個API包,那么我們可以提供一個比較寬的區(qū)間账蓉,如“[1.0.0, 2.0.0)”枚碗,這個區(qū)間包含了最小和最大版本號之間的所有版本。但是如果我們是提供一個服務(wù)接口的實現(xiàn)铸本,那么我們需要使用較窄的區(qū)間來導(dǎo)入依賴肮雨,例如“[1.0.0, 1.1.0)”,意味著包含1.0.0和這個區(qū)間內(nèi)的箱玷,但是不包含1.1.0怨规。這里的不同點在于,一個支持1.0.0的服務(wù)提供者無法支持1.1.0锡足,因為增加的版本號表明有新的功能被添加了進(jìn)來波丰,而提供者無法自動提供新的功能。另一方面舶得,一個服務(wù)消費者掰烟,可以方便地使用1.1.0和1.2.0等版本號,因為它可以忽略新增加的功能。

除了生成導(dǎo)入范圍外纫骑,OSGi構(gòu)建工具(bnd)還可以幫助獲得導(dǎo)出包的正確版本蝎亚。版本號是包的一個屬性,它可以直接寫在包中(通過在 package-info.java 文件中添加 @Version 注解)先馆。當(dāng)包中的內(nèi)容改變的時候发框,一件很重要的事就是修改這個版本號,例如:當(dāng)我們在服務(wù)接口中增加了一個方法時煤墙,我們需要將版本號從1.0.0增加到1.1.0梅惯。構(gòu)建工具檢查版本號是否準(zhǔn)確地反映了所做更改的性質(zhì)。例如番捂,當(dāng)我們添加了方法而忘記修改版本號的時候个唧,構(gòu)建將會失敗,或者我們只是將版本號增加為1.0.1的時候也會如此设预。

最終徙歼,OSGi具有這樣的靈活性:可以在單個應(yīng)用程序中同時部署模塊的多個版本。這種情況會在這樣的場景出現(xiàn):通過傳遞依賴我們引用了一些通用庫的不同版本鳖枕,如 slf4j 或 Guava魄梯。還有一些限制是:我們不能直接在單個模塊中導(dǎo)入包的多個版本,但是在真正需要的時候宾符,具備這樣的能力還是很有用的酿秸。

與之相對的是,JPMS對版本控制基本沒有任何支持魏烫。

在 module-info.java 中沒有辦法為一個模塊指明版本辣苏。在 module-info.class 文件中存在一個版本屬性,但是它并不是來自于 Java 代碼哄褒,目前還不清楚它在實際中該如何使用稀蟋。依賴聲明同樣沒有版本:JPMS模塊只能通過名字來 require 其它模塊,無法指明版本呐赡,當(dāng)然更無法指明版本的范圍退客。這些特性需要由外部工具添加,但這種方法是受限的链嘀,因為 module-info.java 源文件是不可擴(kuò)展的萌狂,并且在該文件內(nèi)也無法使用 Java 注解。

JPMS的需求規(guī)定:在運行時選擇兼容的版本不在支持范圍內(nèi)怀泊。這意味著其它工具將不得不做這項工作茫藏,但沒有合適的元數(shù)據(jù)它們無法完成這項工作。將版本元數(shù)據(jù)存儲在與基本模塊元數(shù)據(jù)相同的描述符中是很自然的霹琼,但這是不可能的刷允。

正如我們提到的一樣冤留,JPMS中禁止在運行時同時包含一個模塊的多個版本碧囊。此外树灶,它禁止多個模塊導(dǎo)出相同的包,甚至禁止重復(fù)的私有包糯而。因此天通,無論其它工具使用什么方法來構(gòu)建一個有效的模塊集合,都需要找到一個解決轉(zhuǎn)遞依賴沖突的方法熄驼。在很多案例中像寒,一個簡單的“方法”是:在多個模塊共同存在的場景下,禁止一些模塊的使用瓜贾。

動態(tài)性

OSGi基于類加載的隔離實現(xiàn)方案有一個不錯的用處:可以支持模塊在運行時被動態(tài)加載诺祸、更新和卸載。這在企業(yè)環(huán)境中似乎并不重要祭芦,事實上大多數(shù)OSGi企業(yè)在部署中都不會使用動態(tài)更新筷笨。的確,OSGi沒有要求你一定要使用動態(tài)更新龟劲!

但是動態(tài)更新在其它環(huán)境中是非常有用的胃夏,比如物聯(lián)網(wǎng)。在數(shù)千臺甚至數(shù)百萬臺設(shè)備上昌跌,通過緩慢或斷斷續(xù)續(xù)的網(wǎng)絡(luò)更新軟件是一件讓人頭痛的事情仰禀。OSGi是少數(shù)技術(shù)之一,可以在任何平臺上直接支持使用最少數(shù)據(jù)量進(jìn)行即時更新:我們只需要發(fā)送實際更改的模塊蚕愤。

最初在2000年答恶,電信運營商在家庭網(wǎng)關(guān)和路由器上使用OSGi構(gòu)建智能家居解決方案的主要原因之一是:能夠在不進(jìn)行固件更新的情況下管理軟件。固件更新不吸引人的原因有很多:下載固件更新通常需要下載兆字節(jié)的軟件到潛在的數(shù)百萬設(shè)備上萍诱;固件是針對設(shè)備設(shè)計的悬嗓,因此你可能會有許多不同的更新來創(chuàng)建和管理部署;測試固件更新需要大量的砂沛、耗時的烫扼、昂貴的壓力測試,每次都要對每個設(shè)備執(zhí)行這個測試碍庵。OSGi顯著簡化了這個過程映企;更新可以應(yīng)用在模塊中,并快速安裝在運行的網(wǎng)關(guān)和路由器上静浴,不需要重啟堰氓;同樣的模塊可以在所有設(shè)備上使用(通常是底層硬件設(shè)備的抽象),重要的是苹享,單元測試可以在更小的軟件集上執(zhí)行双絮,節(jié)省大量的時間浴麻、精力和金錢。一個具體的例子是 Qivicon囤攀,它是一個由德國電信公司成立的行業(yè)聯(lián)盟软免。Qivicon 提供家庭網(wǎng)關(guān),包括:基于OSGi的軟件棧焚挠,后端基礎(chǔ)設(shè)施膏萧、應(yīng)用程序開發(fā)工具以及維護(hù)和支持。通過使用OSGi來搭建基礎(chǔ)生態(tài)系統(tǒng)的方法蝌衔,使得Qivicon的合作伙伴能更快地將智能家居產(chǎn)品推向市場榛泛。

Qivicon 合作伙伴不斷整合新設(shè)備和開發(fā)新的創(chuàng)新增值服務(wù)。這需要復(fù)雜的設(shè)備管理和軟件供應(yīng)能力噩斟,以確保針對特定設(shè)備平臺的軟件組件的依賴性和兼容性管理曹锨。通過利用現(xiàn)有的工業(yè)標(biāo)準(zhǔn)(如 TR-069 和 OMA-DM),這些功能已經(jīng)被寫入OSGi標(biāo)準(zhǔn)規(guī)范中了剃允。

此外沛简,動態(tài)行為不僅僅體現(xiàn)在軟件更新上。

OSGi服務(wù)注冊表本質(zhì)上是動態(tài)的硅急。服務(wù)可以注冊和卸載覆享,與之綁定的相關(guān)組件也會在收到事件通知。服務(wù)允許真實世界不斷變化的狀態(tài)被表示和通知营袜。即使在相對穩(wěn)定的企業(yè)應(yīng)用領(lǐng)域撒顿,這也是相關(guān)的。例如荚板,OSGi服務(wù)可以表示外部數(shù)據(jù)輸入是否可用凤壁,或者是REST服務(wù)的負(fù)載均衡IP地址,甚至是金融市場的開放時間跪另。每個消費服務(wù)的組件可以決定服務(wù)不可用時的反應(yīng)行為:可以繼續(xù)拧抖,或者注銷自身提供的服務(wù)。因此免绿,狀態(tài)的變化被可靠地傳播到任何有影響的地方唧席。

協(xié)同工作與未來發(fā)展

JPMS會在Java 9中發(fā)布。目前有非常多的應(yīng)用程序是用OSGi寫的嘲驾,同時還有很多代碼正在被書寫淌哟。這些代碼是安全的嗎?它們是否需要在JPMS平臺上重新被改寫辽故?

首先需要明確地是:OSGi應(yīng)用可以不用修改代碼繼續(xù)在Java 9上運行徒仓,因為它沒有使用不被支持和內(nèi)部的Java API。對于其他的Java應(yīng)用代碼也是如此誊垢。OSGi只使用了被支持的Java API掉弛,并且Oracle承諾Java 9不會使這些應(yīng)用奔潰症见。你在使用Java 9時遇到的問題可能是來自一些使用了JDK內(nèi)部類型的類庫,因為這些類型在Java 9中無法被訪問殃饿,除非通過特殊的配置標(biāo)志進(jìn)行訪問谋作。OSGi的用戶將能更好地應(yīng)對這個改變,因為它們的模塊具有顯式的依賴列表壁晒。通常瓷们,Java應(yīng)用會在類路徑上放置多個Jar包,與它們相比秒咐,基于OSGi的應(yīng)用對于平臺依賴的范圍會更加清晰。

一個最基本兼容模式是碘裕,OSGi框架和bundle會存在于JPMS的“未命名”模塊中携取。OSGi還會繼續(xù)提供所有已經(jīng)存在的隔離性特性,包括它功能強(qiáng)大的服務(wù)注冊和動態(tài)加載能力帮孔。你對OSGi的投資是安全的雷滋,而且OSGi仍然是新項目的一個好選擇。

但我們希望能比這做得更好文兢。當(dāng)OSGi運行在已經(jīng)模塊了的Java 9平臺上時晤斩,我們應(yīng)該能夠充分利用平臺中的模塊。例如姆坚,可以為一個OSGi bundle聲明它依賴的平臺模塊澳泵,這意味著一個OSGi bundle可以直接依賴一個JPMS模塊。OSGi框架應(yīng)該關(guān)注那些運行時的依賴兼呵,并且工具應(yīng)該能夠根據(jù)這些依賴準(zhǔn)備運行時環(huán)境兔辅。

此時事情已經(jīng)看起來很不錯了。在我2015年11月的一篇博客中击喂,我對這個概念進(jìn)行了驗證性描述维苔,在JPMS上構(gòu)建并運行了OSGi程序。我詳細(xì)介紹了如何讓OSGi bundle在基礎(chǔ)平臺的JPMS模塊中聲明依賴懂昂。我展示了OSGi是如何拒絕這樣的一個bundle:它依賴的JPMS模塊不在平臺中介时。我沒有在運行時提供一個工具原型,但是通過所有描述的部分已經(jīng)可以構(gòu)建這樣的一個工具了凌彬。

圖3描繪了未來兩個機(jī)制可以如何一起工作沸柔。我們可以看到:Bundle A 導(dǎo)入了包 javax.activation,這個包來自JPMS中導(dǎo)出的 javax.activation 模塊饿序。交互層知道平臺中包含了這個模塊勉失,會運行OSGi來處理它。當(dāng)Bundle A遷移到Java 9上時原探,并不需要做任何改變乱凿。Bundle B使用了 java.net.http 包顽素,這個包來自JPMS的 java.httpclient 模塊,但是它無法在OSGi中Import-Package部分進(jìn)行聲明徒蟆,因為它是以 java. 開頭的(需要注意的是胁出,所有的 bundle 和 moudle 都隱含地依賴 java.base)。

因此段审,我們提出了一個新的OSGi頭部全蝶,稱作“Require-PlatformModule”,它用來表示對JPMS中模塊的依賴寺枉。這樣當(dāng)Bundle B沒有包含 java.httpclient module 模塊的時候抑淫,OSGi框架能夠在Bundle B中“快速失敗”。這同時還可以使得工具能夠為應(yīng)用構(gòu)建一個完整的運行時環(huán)境姥闪,這個環(huán)境是JPMS中的 modules 和OSGi中的 bundles 的最小集合始苇。

再次聲明,這個工作是一個非官方的概念證明筐喳。最終催式,OSGi如何和JPMS進(jìn)行交互將由規(guī)范來處理。

圖3 OSGi-JPMS相互協(xié)作的概念證明

結(jié)論

JPMS避归,通過Jigsaw原型項目荣月,對Java平臺本身的模塊化工作是非常出色的。通過這個工作梳毙,可以構(gòu)建更小的運行時環(huán)境哺窄,只需要包括Java平臺中任務(wù)依賴的部分。

然而作為應(yīng)用的模塊化規(guī)范顿天,JPMS存在嚴(yán)重的缺陷堂氯。缺少對版本控制的支持是一個令人震驚的遺漏,而且在沒有外部工具提供額外元數(shù)據(jù)的情況下牌废,很難在構(gòu)建應(yīng)用程序的過程中實現(xiàn)版本管理咽白。整個模塊(whole-module)依賴聲明形式將會導(dǎo)致獲得更多的傳遞依賴項,這將削弱它們遷移到更小平臺的能力鸟缕。無法通過反射來獲得未導(dǎo)出模塊中的類型晶框,這樣將會無法使用Java生態(tài)系統(tǒng)中已有的一些框架。

這些設(shè)計對于JDK本身來說可能是合適的:這增加了平臺的健壯性和安全性懂从,同時沒有破壞所有Java應(yīng)用的向后兼容性授段。但是它們的做法只是一種折中,對于應(yīng)用的模塊化來說番甩,這個設(shè)計很不友好侵贵。

所以O(shè)SGi的未來看起來是光明的:通過將OSGi和整理過的模塊化Java平臺相結(jié)合,我們可以使這兩個生態(tài)都獲得更好的發(fā)展缘薛。OSGi已經(jīng)具有了16年的經(jīng)驗窍育,并且遇到和解決了JPMS還沒有考慮過的問題卡睦。OSGi的開發(fā)工具和運行時生態(tài)是廣泛和深入的。在一個長期有效漱抓、獨立的標(biāo)準(zhǔn)機(jī)構(gòu)的支持下表锻,它的未來是得到保障的。你還在等什么那乞娄?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瞬逊,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子仪或,更是在濱河造成了極大的恐慌确镊,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,914評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溶其,死亡現(xiàn)場離奇詭異骚腥,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)瓶逃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評論 2 383
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來廓块,“玉大人厢绝,你說我怎么就攤上這事〈铮” “怎么了昔汉?”我有些...
    開封第一講書人閱讀 156,531評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長拴清。 經(jīng)常有香客問我靶病,道長,這世上最難降的妖魔是什么口予? 我笑而不...
    開封第一講書人閱讀 56,309評論 1 282
  • 正文 為了忘掉前任娄周,我火速辦了婚禮,結(jié)果婚禮上沪停,老公的妹妹穿的比我還像新娘煤辨。我一直安慰自己,他們只是感情好木张,可當(dāng)我...
    茶點故事閱讀 65,381評論 5 384
  • 文/花漫 我一把揭開白布众辨。 她就那樣靜靜地躺著,像睡著了一般舷礼。 火紅的嫁衣襯著肌膚如雪鹃彻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,730評論 1 289
  • 那天妻献,我揣著相機(jī)與錄音蛛株,去河邊找鬼团赁。 笑死,一個胖子當(dāng)著我的面吹牛泳挥,可吹牛的內(nèi)容都是我干的然痊。 我是一名探鬼主播,決...
    沈念sama閱讀 38,882評論 3 404
  • 文/蒼蘭香墨 我猛地睜開眼屉符,長吁一口氣:“原來是場噩夢啊……” “哼剧浸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起矗钟,我...
    開封第一講書人閱讀 37,643評論 0 266
  • 序言:老撾萬榮一對情侶失蹤唆香,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后吨艇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體躬它,經(jīng)...
    沈念sama閱讀 44,095評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,448評論 2 325
  • 正文 我和宋清朗相戀三年东涡,在試婚紗的時候發(fā)現(xiàn)自己被綠了冯吓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,566評論 1 339
  • 序言:一個原本活蹦亂跳的男人離奇死亡疮跑,死狀恐怖组贺,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情祖娘,我是刑警寧澤失尖,帶...
    沈念sama閱讀 34,253評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站渐苏,受9級特大地震影響掀潮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜琼富,卻給世界環(huán)境...
    茶點故事閱讀 39,829評論 3 312
  • 文/蒙蒙 一仪吧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧公黑,春花似錦邑商、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,715評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至朝蜘,卻和暖如春恶迈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,945評論 1 264
  • 我被黑心中介騙來泰國打工暇仲, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留步做,地道東北人。 一個月前我還...
    沈念sama閱讀 46,248評論 2 360
  • 正文 我出身青樓奈附,卻偏偏與公主長得像全度,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子斥滤,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,440評論 2 348