Java多是近20年來最成功的開發技術,因其具有通用性、高效性、平臺移植性和安全性而成爲不一樣硬件平臺理想的開發工具。從筆記本電腦到數據中心,從遊戲控制檯到科學超級計算機,從手機到互聯網,Java技術無處不在。css
Java可以讓程序員使用同一種語言爲服務器、智能卡、移動電話和嵌入式設備開發程序,極大地提高了軟件的研發效率。不過,僅靠統一的語言還不足以讓軟件業迅速提高至成熟的工業化階段。不一樣軟件系統、不一樣硬件設備下的程序都常常會有相同的業務需求和設備間交互通訊的需求,例如不少設備都須要互聯網接入的功能,若是通用於不一樣設備的網絡標準件不存在,那就只能爲每一個設備都開發一個鏈接互聯網的模塊,這樣效率和質量都難以保證。假如把開發中常常遇到的需求進行抽象,將它們統一規範起來做爲標準件提供,任何設備都經過預約義好的協議和接口來使用這些標準件,那麼構造一個大型程序的主要工做極可能就只是根據需求選擇合適的模塊,而後再寫少許的黏合代碼而已。程序員
標準件是區別小手工做坊和大工業化最明顯的標誌。今天,我的計算機的硬件已經到達了工業化階段,不管哪一個公司生產的顯示器、鍵盤、鼠標、內存和CPU,都遵循統一規範的接口工做。要得到不一樣功能、性能的計算機,只要選擇適當的硬件模塊進行組裝便可。與此相對的,大部分計算機軟件都仍是從零開始進行編碼開發的。軟件業還遠不如硬件成熟,可是軟件工業化是一股不可逆轉的潮流,實現這個目標的第一步就是要制定不一樣功能模塊的標準,以及模塊間的黏合及交互方式。Java業界內已經有了不少的技術規範,例如EJB、JTA、JDBC、JMS等,欠缺的是一個組織者或扮演黏合劑的角色,直到Java有了OSGi……數據庫
1.1 什麼是OSGi
OSGi(Open Service Gateway Initiative,直譯爲「開放服務網關」)其實是一個由OSGi聯盟(OSGi Alliance,如圖1-1所示)發起的以Java爲技術平臺的動態模塊化規範。緩存
圖1-1 OSGi聯盟安全
OSGi聯盟是由Sun Microsystems、IBM、Ericsson等公司於1999年3月成立的一個世界性的開放標準化組織,最初的名稱爲Connected Alliance,該組織成立的主要目的本來在於使服務提供商經過住宅網關爲各類家庭智能設備提供服務。最初的OSGi規範也只是關注於嵌入式領域,前三個版本的OSGi規範主要知足諸如機頂盒、服務網關、手機等應用環境的模塊化需求。從第四個版本開始,OSGi將主要關注點轉向了Java SE和EE領域,而且在這些領域中得到了很大的發展,成爲Java平臺事實上的模塊化規範。服務器
隨着OSGi技術的不斷髮展,OSGi聯盟的成員數量已經由最開始的幾個增加到目前超過100個,不少世界著名的IT企業都加入到OSGi的陣營之中,如Adobe、IBM、Oracle、SAP、RedHat和Siemens等。它們推出的許多產品都支持OSGi技術,甚至產品自己就使用了OSGi技術構建,例如IBM的WebSphere、Lotus和JAZZ,Oracle的GlassFish和Weblogic,RedHat的JBoss,Eclipse基金會的Eclipse IDE、Equinox及之下的衆多子項目,Apache基金會的Karaf、Aries、Geronimo、Felix及之下的衆多子項目等。這些IT巨頭的踊躍參與,也從側面證實了OSGi技術有着很是廣闊的市場前景。網絡
OSGi技術的影響同時也延伸到了Java社區,JSR–232提案的經過說明OSGi技術已經被Java ME領域所承認,而 JSR–291提案則奠基了OSGi技術在Java SE和Java EE領域標準模塊化規範的地位(OSGi與Java模塊化規範的歷史將在1.1.2節會詳細介紹)。架構
OSGi的諸多優秀特性,如動態性、模塊化和可擴展能力逐漸被愈來愈多的開發者所認識和欣賞,愈來愈多的系統基於OSGi架構進行開發。在這些系統的開發過程當中,又會向OSGi提出一個又一個新的需求,因此OSGi規範所包括的子規範與技術範疇也在不斷髮展、日益壯大,如圖1-2所示。框架
圖1-2 OSGi及相關技術分佈式
今天,OSGi的已經再也不是原來Open Service Gateway Initiative的字面意義能涵蓋的了,OSGi聯盟給出的最新OSGi定義是The Dynamic Module System for Java,即面向Java的動態模塊化系統。
2012年7月,OSGi聯盟發佈了最新版的OSGi R5.0規範,此次發佈的規範包括OSGi核心規範R5.0和OSGi企業級規範R5.0。在Java SE領域,Eclipse和NetBean兩款集成開發工具的成功已經徹底證實了OSGi在桌面領域是能擔當重任的。最近兩三年來,OSGi的發展方向主要集中在Java EE領域,在OSGi企業專家組(EEG)的努力下,OSGi的企業級規範R5.0版相比兩年前發佈的R4.2版又增長了許多新的內容,OSGi技術在服務端和企業級領域正迅速走向成熟。
1.1.1 OSGi規範的演進
OSGi在R4版以前都處於初級階段,規範的主要關注點是在移動和嵌入式設備上的Java模塊化應用。在這個初級階段中有一些很成功的案例,好比BMW(寶馬)汽車使用OSGi架構實現的多媒體設備控制程序(內部是西門子VDO系統),要使用不一樣型號的電子設備,只更換對應程序模塊便取得了很好的效果。可是初級階段的OSGi在Java其餘主流應用領域(企業級、互聯網、服務端、桌面端等)的影響力還比較有限,所以下面簡要介紹這部分的歷史。OSGi規範在初級階段一共發佈了三個版本:
- OSGi Release 1 (R1):2000年5月發佈。
- OSGi Release 2 (R2):2001年10月發佈。
- OSGi Release 3 (R3):2003年3月發佈。
從OSGi R4版開始,OSGi的目標就從「在移動和嵌入式設備上的Java模塊化應用」發展爲「Java模塊化應用」,去掉了「在移動和嵌入式設備上的」這個限定語,這意味着OSGi開始脫離Java ME的約束,向Java其餘領域進軍。同時也意味着OSGi須要考慮如何去遷移遺留的異構系統、如何去支持大規模開發等非嵌入式領域的問題了。所以,OSGi R4版規範的複雜度相應地高出R3版許多。筆者能夠給出兩個最直觀的數據:規範文檔的頁數從R3的450頁增長到900頁,規範中定義的外部接口(統計API中public方法)數量從R3的661個增長到1432個。
OSGi R4版本分爲兩個部分, 2005年10月發佈的核心規範(包含服務綱要規範)和2006年9月發佈的移動設備規範(移動設備規範已中止發展,目前最新的OSGi移動設備規範依然是這個版本)。從更具體的角度來說,OSGi R4解決了R3的許多遺留問題和限制,如下列舉了部分在覈心規範中比較關鍵的改進:
- 在OSGi R3版本中,模塊導出的Package是全局惟一的,不容許同一個Package存在多個版本。這點限制放在資源受限的嵌入式環境中通常不會有問題,可是放在整個Java領域就不妥了,由於引用不一樣版本的第三方包對於規模稍大一點的程序來講是很常見的事情。
- OSGi R3中的模塊缺少對模塊自己的擴展機制,全部的資源、代碼都必須在模塊中是靜態存在的,沒法運行時動態添加。在OSGi R4中,出現了Fragment Bundle的概念。
- OSGi R3的Package導入和導出不管是版本、可見性和可選擇性都很粗糙,例如在導入時指明一個Package的版本,語義就只能是導入不小於這個版本的Package,而對於要明確具體版本範圍(如[2.5,3.0))的需求就不適用;又如在導出Package時,一個Package中的全部類要麼所有導出,要麼所有隱藏。在OSGi R4中改進了version參數,也爲導入導出加入了許多子參數來方便精確過濾範圍。
除了在覈心規範中對R3版的改進外,許多目前很是經常使用的、在服務綱要規範中的OSGi服務也是在R4版纔開始出現的。這些服務對提高開發人員的工做效率及系統的魯棒性有很大幫助,例如R4版首次出現的聲明式服務就是對R3版以前的程序化服務模型的重大改進。 儘管從OSGi R3到OSGi R4發生了很大的變化,R4版規範依然保持了很好的向後兼容性,絕大部分能運行於OSGi R3的模塊均可以不經修改地遷移到OSGi R4之中。
2007年5月發佈的OSGi R4.1是一個修正版性質的規範,只是核心規範發生了很小的變化,服務綱要規範和移動設備規範並無跟隨發佈R4.1版,整個R4.1版沒有新增任何服務。OSGi R4.1版本的推出,最重要的任務是適配JSR-291提案,讓JSR-291提案順利經過JCP的投票,成爲整個Java業界標準的一部分。
在OSGi R4.1版本中,值得一提的改進是處理了Bundle延遲初始化的問題,增長了Bundle-ActivationPolicy標識來指明Bundle的啓動策略。在此以前,OSGi實現框架只能經過本身的非規範的標識來完成相似的事情,例如Equinox的私有的Eclipse-LazyStart標識。
2009年9月,OSGi R4.2版核心規範發佈;在次年3月,還發布了OSGi R4.2企業級規範。OSGi R4.2是一個包含了許多重要改進的版本。首先,隨着OSGi實現框架的數量逐漸增多,OSGi R4.2開始着手解決OSGi框架自身的啓動問題,提供了操做OSGi框架的統一API。在此以前,啓動Felix、Equinox、Knopflerfish或其餘OSGi框架,必須使用徹底不一樣的私有API來實現,這點不利於程序在不一樣OSGi上實現平滑遷移。另外,OSGi R4.2還向開發者提供了影響OSGi框架運做的能力,如Bundle Tracker、Service Hooks這些工具的出現,讓由非OSGi實現框架的開發人員去實現OSGi系統級的模塊成爲可能。
在具體服務方面,OSGi R4.2的主旋律是企業級服務的改進。許多企業級服務在這個版本中首次出現,例如遠程服務規範和Blueprint容器(提供依賴注入和反轉控制的容器,相似於Spring的功能)規範。說到企業級服務,OSGi R4.2專門獨立發佈企業級服務規範的一個重要任務就是解決OSGi與Java EE服務之間關係的問題。Java EE體系中的許多重要服務如JNDI、JPA和JDBC等在企業級開發中都是不可或缺的,所以在OSGi R4.2中相應定義了JNDI、JPA和JDBC等服務規範,將Java EE的服務引入到OSGi容器中來。
除此以外,OSGi R4.2還制定了Web Applications規範,使OSGi中包含Web頁面的模塊能夠使用標準WAR格式來打包(打包後的產品爲以.wab爲擴展名的JAR格式文件),容許將這些模塊直接安裝到支持OSGi和Web Applications規範的應用服務器之中。
2011年4月和2012年3月,分別發佈了OSGi R4.3的核心規範和服務綱要規範。在這個版本中,OSGi的API接口終於開始使用已經有8年曆史的、從Java SE 5開始提供的泛型。OSGi對Java平臺版本遲緩響應,很大程度是由於顧及到嵌入式環境的虛擬機版本,不少設備尚未升級到Java 1.5,同時還顧及其中存在的遺留系統。OSGi R4.3有了這樣的變化,也從側面說明OSGi的重心已經開始向服務端應用等領域偏移了。
OSGi R4.3的另外一個重要改進是在覈心規範中添加了Bundle Wiring API子規範,該規範引入了Capabilities和Requirements的概念。在此以前,OSGi中的依賴單元要麼是某個Package,要麼是整個Bundle(分別使用Import-Package和Require-Bundle標識來描述),這種粒度的依賴單元可以知足代碼上的依賴須要,卻沒法描述某些非代碼的依賴特性,例如說明一個功能要依賴某個Java虛擬機版本、依賴某種架構的操做系統、依賴某些資源文件或依賴必定數量的CPU或內存等。之前雖然能夠使用Bundle-RequiredExecutionEnvironment標識來描述部分執行環境的特性(如指明JDK版本是Java SE 6),可是有一些特性不是在執行環境中自然存在的,是由某個Bundle安裝後帶來的,有了Require-Capability和Provide-Capability標識以後,才能夠精確描述這類依賴關係。
繼在OSGi R4.2中引入Service Hooks以後,OSGi R4.3大幅增長了OSGi的Hooks掛接點數量,新增了Weaving Hook、Resolver Hook、 Bundle Hook、Weaving Hook和Service EventListener Hook。
Weaving Hook讓用戶模塊能夠得到在其餘類加載時動態植入加強的能力。Resolver Hook和Bundle Hook代替了之前的OSGi框架嵌套和組合模塊(Composite Bundle)的功能,讓用戶能夠建立虛擬的模塊集合,使不一樣集合之間的模塊互不可見(這點在OSGi R5中提供了更完美的解決方案)。Service EventListener Hook讓用戶能夠插手服務事件分派的過程。
2012年7月,OSGi R5發佈(同時發佈了核心規範和企業級規範的OSGi R5版本),這是目前最新的OSGi規範版本。OSGi R5的一個主要目標是創建一套基於OSGi的模塊倉庫系統(爲下一步的OSGi in Cloud作準備)。Apache Maven已經建成了相似的倉庫系統,它的中央倉庫中保存了Java業界中許多項目的依賴信息和JAR包。其實OSGi在這個領域本應有着得天獨厚的優點,模塊的元數據信息在某種意義上就是依賴描述的信息,但遲遲未在規範上踏出這一步。在OSGi R5出現以前,就已經有了Equinox P二、OSGi Bundle Repository(OBR)等技術出現,在OSGi R5版規範中提出的Subsystem Service子規範和Repository Service子規範終於把這些技術統一塊兒來。
OSGi R5還對許多以前發佈的子規範進行了更新和功能加強,例如JMX Management Model規範開始支持Bundle Wiring API了,Configuration Admin在這個版本中可以支持多個Bundle共享同一個配置對象,聲明式服務規範開始支持註解(這些註解用於供BndTools這類工具自動生成XML配置文件之用,實際上OSGi運行期仍是沒有使用泛型以外的Java SE 5後的語法特性)。
1.1.2 Java模塊化規範之爭
通過近20年的發展,Java語言已成爲今日世界上最成功、使用的開發者人數最多的語言之一,Java世界中無數商業的或開源的組織、技術和產品共同構成了一個無比龐大的生態系統。
與大多數開發人員的廣泛認知不一樣,Java的生態系統和演進路線並非由Sun Microsystems公司來決策和管理的。雖然Sun公司擁有「JavaTM」這個商標的全部權,而且擁有Java中使用最普遍的HotSpot虛擬機和Sun JDK,但它並不能直接制定Java世界中的規則、肯定Java技術的發展走向。
1998年,在Sun公司的推進下成立了JCP(Java Community Process)組織,這個組織負責制定Java的技術標準,發佈技術標準的參考實現(RI)和用於檢驗標準的技術兼容包(TCK)。目前,除了Sun(目前是Oracle繼承了Sun的席位)公司外,還有Google、IBM、Motorola、Nokia、Sybase、SAP等數以百計的公司、組織和獨立我的參與了JCP組織,共同監督和維護Java標準的制定。這些參與者中的16位表明組成了JCP執行委員會(JCP Executive Committees,一共有兩個這樣的委員會,分別對應Java SE/EE方向和Java ME方向),對提交給JCP的提案進行投票表決。
JCP容許任何組織或我的對Java的演進路線提出建議,這些建議在審查立項後會以JSR(Java Specification Requests)的形式造成正式的規範提案文檔;在通過專家組審覈和執行委員會投票經過以後,這些JSR文檔就將成爲正式的Java技術規範。J2EE、EJB、JSP、JDBC、JMX、JVMS等規範都由對應的JSR文檔「孵化」而來,甚至連JCP自己的組織和運做方式也是由特定的JSR文檔進行定義的。
以上介紹的內容雖然與OSGi沒有直接關係,可是它們是讀者瞭解後面介紹的OSGi與Java之間關係的必要背景知識。
OSGi源於JSR-8(Open Services Gateway Specification,開放服務網關規範),這是一份由Sun發起並主導(共同發起的還有IBM、Ericsson和Sybase等公司)、在1999年3月提交到JCP的規範提案。這份規範定義了不一樣設備之間服務互相依賴和調用的交互接口。1999年,Java 2剛發佈不久,互聯網也剛剛興起,「支持各類移動設備、嵌入式設備、智能家電」這個最初創建Java語言的目標,對於Java來講依然是最重要領域之一。
不過,JSR-8提案很快(1999年5月,即提交以後的2個月)就被髮起者撤回。撤回並非由於這份JSR不夠資格成爲Java規範發佈,主要是發起者但願另外創建一個獨立於JCP的組織來發展運做這份規範,讓更多不適合參與到JCP的設備廠商可以參與OSGi的規範制定。所以,1999年獨立於JCP的OSGi聯盟成立,並於2000年發佈了OSGi規範的第一個版本:OSGi R1.0。
在OSGi的前三個版本中,OSGi主要領域依然維繫在移動和嵌入式設備之上,在這三個版本的發展中Sun公司起了很大的推進做用,這段時間可謂是OSGi和Sun的蜜月期。好比Sun的JES(Java Embedded Server)就是當時使用最普遍的OSGi R2的實現。從OSGi R4開始,OSGi開始嘗試跨越移動和嵌入式領域的限制,進入Java SE/EE領域,與此同時,OSGi聯盟的各個成員在發展和商業選擇上也產生了分歧,各自(主要是IBM和Sun)都在爭奪OSGi聯盟的主導權。在這個過程當中各廠商是如何爭奪規範控制權的咱們不得而知,總之最終的結果是Sun公司於2006年離開了當年它一手主導創建的OSGi聯盟。OSGi規範分爲面向Java主流領域的OSGi R4核心規範和依然專門面向嵌入式和移動領域的OSGi移動設備規範(即JSR-232 Mobile Operational Management,OSGi R4 Mobile與JSR-232的內容是徹底一致的)。
在今天看來,Sun的離開偏偏證實了當時它在Java模塊化方向上的錯誤。OSGi R4的目標平臺轉變爲Java SE/EE,進軍桌面、服務端和互聯網的舉措得到了很大的成功,關於這點不得不提到在IBM支持下Eclipse基金會對OSGi快速流行所作出的貢獻。自Eclipse 3.0 M4版本開始,這款著名的集成開發工具被重構爲徹底基於OSGi架構實現的產品,支持Eclipse運行的底層框架Equinox成爲OSGi R4.x使用最普遍的實現框架。伴隨着Eclipse IDE的流行,OSGi迅速在Java ME之外的領域站穩腳跟。許多人(包括筆者)都是從Eclipse開始關注OSGi的,IBM的不少後續產品,如WebSphere、JAZZ等都繼續支持OSGi或直接基於OSGi來構建,其餘公司也迅速跟進。
OSGi R4的迅速流行帶來一個強烈的信號:Java SE/EE支持模塊化已經成爲一股不可逆轉的潮流,支持模塊化的呼聲已經強大到令Sun公司不能再忽視的程度。Sun公司指望能借助JCP的力量從新爭奪Java模塊化規範的控制權。
2006年10月,由Sun公司提交的JSR-277規範提案(Java Module System,Java模塊化系統)發佈了第一個早期預覽版(Early Draft Review);2007年年末,Sun攜帶着JSR-277從新加入OSGi聯盟。
JSR-277是一個全靜態的模塊化規範,它在模塊化和依賴描述方面與OSGi有着類似的能力,在構建模塊倉庫(Repository)上對比當時的OSGi規範佔有必定優點(OSGi這方面的弱點在2012年7月OSGi R5發佈並擁有了Subsystem Service和Repository Service以後已經被填補)。可是JSR-277是徹底靜態的,沒有任何關於動態化的考慮,這樣模塊就沒法在運行時安裝、更新和卸載,所以也就不存在類空間一致性、類和類加載器卸載等問題。這點相對於OSGi的動態模塊化來講是極大的退步。另外JSR-277引入新的「.jam」格式文件做爲模塊分發格式也被你們所詬病。OSGi技術專家、OSGi聯盟主席Peter Kriens在OSGi聯盟的官方博客上發表文章批評道:「JSR-277的目標如同兒戲,只能至關於OSGi在8年前的技術水平」。
在JCP中爭奪模塊化規範控制權,對於Sun來講會比在OSGi聯盟中更爲有利。Sun在JCP擁有很大的影響力,它是JCP的發起者,擔任JCP的主席,在執委會中擁有無須選舉的無限期執委會投票權(其餘15個執委席位三年選舉一次),Sun確定但願能永遠保持在JCP中的領導地位,可是JCP的其餘成員都但願可以在Java的規範和發展路線上擁有更大的話語權。這樣,不可避免會產生一些利益衝突。Sun力挺JSR-277,但願用它代替OSGi成爲Java模塊化標準,IBM則將OSGi R4.1提交到JCP成爲JSR-291(Dynamic Component Support for Java SE ,Java SE動態組件支持)來與JSR-277對抗,這樣,在OSGi聯盟中的規範之爭的戰場又從新回到JCP之中。
這兩個JSR競爭的結果是JSR-277沒有獲得經過,儘管Sun曾經作出了一些讓步,好比承諾JSR-277能夠引用和操做OSGi的遺留模塊,它最終仍是沒有獲得足夠的支持,被廢止在早期預覽版階段。另外一方面,在對JSR-291進行表決時,雖然Sun明確投了反對票,可是JSR-291仍然在JCP執委會最終投票中經過。這樣,OSGi終於確立了Java惟一的模塊化規範的地位。不過,事情並無結束,JSR-291獲得經過並不意味着OSGi規範馬上就會成爲現實。
雖然OSGi R4.1在2007年5月經過投票以後就應該是正式的Java規範,可是Sun依然在JSR-316(Java Platform, Enterprise Edition 6 Specification,Java企業版規範第6版,這個規範提案在2007年7月提交給JCP,2009年12月發佈最終版,提交時JSR-277與JSR-291之爭已塵埃落定)的規範目標中明確寫道:「爲了更好地支持這個平臺(指Java EE 6)在擴展性方面的目標,應該有一個更加寬泛的模塊化概念。這項工做正由‘JSR-277 Java模塊系統’來實現,它的目標平臺是Java SE 7。咱們預期Java EE 7將創建在這項技術的基礎上,所以咱們將推遲任何可能與未來的版本衝突的技術規範」。在這段話中所謂的「可能與未來的版本衝突的技術規範」毫無疑問就是JSR-291了。Sun(當時已經被Oracle收購了)這種獨斷獨行地堅持本身的JSR-277而無視JSR-291的行爲招來了許多非議。可是非議沒法解決問題,Sun仍然實質性地控制着JDK的發展,最終結果就如JSR-316中的那句話所表達的那樣,整個Java SE 6期間沒有任何模塊化相關的改進以JDK功能的形式進入到Java平臺中。Sun對待OSGi的態度不該解讀爲Sun反對Java模塊化,相反,這是Sun極爲重視Java模塊化的體現,它必定要把Java模塊化的主導權抓在手中。儘管Sun的作法拖延了Java模塊化的進程,但模塊化依然是不可避免地向前發展了,到Java SE 7中又如何呢?
講到Java SE 7的模塊化,咱們不得再也不多介紹一個規範提案:JSR-294(Improved Modularity Support in the Java Programming Language,Java語言的模塊化改進)。如此之多(提交的時間很集中,而且是並行發展的,在JSR-294提交時JSR-277並無被廢止)的JSR來解決重複的問題在JCP歷史上也是極爲罕見的。這個規範提案的提交者也是Sun公司,它試圖在Java語言和Java虛擬機層面上對模塊化進行支持,直接修改JLS(Java語言規範)和JVMS(Java虛擬機規範),加入module關鍵字和超級包(Super Package)等概念。JSR-294的模塊化實現思想與OSGi的差別是很是大的,通俗地講,OSGi是在Java平臺之上創建的模塊化,而JSR-294是直接在Java平臺以內創建的模塊化。
從純粹技術角度來看,Java模塊化若是真能經過直接修改Java語法、Class文件格式和Java虛擬機來實現,咱們相信這種實現方案的性能、完善程度確定可以超越OSGi,僅從技術角度看,這種改進方式無疑是Java模塊化的最佳結果。不過,修改Java語法在JCP中從來都是「慎重而敏感的話題」,增長新的語言特性相對緩慢,這點也是社區管理的劣勢。對比一下微軟一家單獨掌控的C#語言,就能看出明顯差距。
話題再回到JSR-294,很遺憾,這個規範提案的結果與JSR-277同樣,也被廢棄在早期預覽版階段。Sun彷佛早就預料到這個結果,它在提交JSR-294的同時,就在OpenJDK中啓動了Jigsaw項目的孵化進程。Jigsaw項目最開始的目標是做爲JSR-294的參考實現(RI),可是該項目的開發過程倒是在jigsaw-dev郵件列表上進行的,該郵件列表遊離於JSR-294專家組的郵件列表以外。目前的種種跡象代表,Sun決定讓Jigsaw項目採起「SunJDK專有的方式」來實現Java語言模塊化,JSR-294沒有獲得經過,也就意味着Jigsaw項目是Sun私有的,使用了Jigsaw的Java程序沒法運行於其餘公司提供的JDK之上。所以,即便Jigsaw自己的設計再好,只要沒法作到「一次編譯,處處運行」的模塊化,就必然是對Java語言最重要一塊基石的巨大損害。
很難相信Sun最後會以私有化的方式強行推出Jigsaw,這是很是不明智的。最後的結果確定還要從新激活JSR-294,或者再提交另一個JSR使之在JCP上經過,在此以前,Jigsaw只能無限期拖延下去。目前Jigsaw已經拖得足夠長了,最初它是做爲Java SE 7的特性進行設計的,後來因Java 7進度壓力被推遲到Java 8之中,在2012年7月,在Jigsaw項目的主頁上宣佈它將進一步被延遲到Java 9中發佈。這樣致使的結果是,即便後續一切順利,用戶也要到2015年9月才能見到Jigsaw,那時已是OSGi出現的16年以後了;再等到Java 9被應用到主流的生產環境中,Jigsaw就顯得更加遙遙無期了。若是系統要兼容Java 2至Java 8平臺,OSGi仍是惟一的選擇。Jigsaw不得不正視OSGi事實上的模塊化規範的地位,創建了一個名爲的Penrose子項目讓Jigsaw能夠與OSGi互相操做。
目前OSGi是Java世界中惟一的模塊化規範,從純技術角度看,它未必是最早進的模塊化技術,從學習使用來看,它也不是使用最簡單方便的模塊化技術。可是從整個Java業界總體來看,OSGi確實是過去、如今乃至將來至少5年內可預見的最有生命力、最標準、使用範圍最普遍的Java模塊化技術。隨着Java應用規模的日益龐大,愈來愈多的大型系統使用OSGi架構進行建設,所以,OSGi是具備廣闊發展前景和使用、學習價值的。
1.2 爲何使用OSGi
沒有什麼技術是萬能的,任何一門技術都有它的適用場景和最佳實踐方法。OSGi不僅是一門技術,更多的是一種作系統架構的工具和方法論,若是在不適用的場景中使用OSGi,或者在適用的場景中不恰當地使用OSGi,都會使整個系統產生架構級的缺陷。所以,瞭解何時該用OSGi是與學會如何使用OSGi一樣重要的事情。
每一個系統遇到的業務環境都是不同的,筆者不但願以經驗式的陳述去回答「何時該用OSGi」或 「爲何要使用OSGi」這樣的問題,而試圖經過幾個問題的討論和利弊權衡,讓讀者本身去思考爲何這些場景適用OSGi。若是讀者是第一次經過本書接觸OSGi,那麼可能對某些討論的內容會感到困惑,筆者建議儘量在閱讀徹底書或者在準備真正在項目中使用OSGi的時候,再回過頭讀一遍本節的內容。
1.2.1 OSGi能讓軟件開發變得更容易嗎
不能否認,OSGi的入門門檻在Java衆多技術中算是比較高的,相對陡峭的學習曲線會爲第一次使用OSGi開發系統的開發人員帶來額外的複雜度。
OSGi規範由數十個子規範組成,包含了上千個不一樣用途的API接口。OSGi規範顯得這樣龐雜的主要緣由是實現「模塊化」自己須要解決的問題就很是多。模塊化並不只僅是把系統拆分紅不一樣的塊而已—這是JAR包就能作的事情,真正的模塊化必須考慮到模塊中類的導出、隱藏、依賴、版本管理、生命週期變化和模塊間交互等一系列的問題。
鑑於OSGi自己就具備較高的複雜度,「引入OSGi就能讓軟件開發變得更容易」不管如何是說不通的,小型系統使用OSGi可能致使開發成本更高。可是這句話又不是徹底錯誤的,隨着系統不斷髮展,在代碼量和開發人員都達到必定規模以後,OSGi帶來的額外成本就不是主要的關注點了,這時候的主要矛盾是軟件規模擴大與複雜度隨之膨脹間的矛盾。如圖1-3所示,代碼量越大、涉及人員越多的系統,軟件複雜度就會越高,二者成正比關係。這個觀點從宏觀角度看是正確的,具體到某個系統,良好的架構和設計能夠有效減緩這個比率。基於OSGi架構的效率優點在這時候才能體現出來:模塊化推進架構師設計出能在必定範圍內自治的代碼,能夠使開發人員只瞭解當前模塊的知識就能高效編碼,也有利於代碼出現問題時隔斷連鎖反應。OSGi的依賴描述和約束能力,強制開發人員必須遵循架構約束,這些讓開發人員「不自由」的限制,在系統規模變大後會成爲開發效率的強大推進力。
圖1-3 引入OSGi對軟件複雜度的影響
能夠用一個更具體的場景來論述上面的觀點,解析OSGi架構如何在開發效率上發揮優點。有經驗的架構師會有這樣的感覺:設計一個具備「自約束能力」的系統架構很是不容易。最多見的狀況是設計人員設想得很美好,開發人員在實現時作出來的產品卻不是那樣。大部分軟件公司是經過「開發過程」、「編碼規範」、「測試驅動」,甚至「人員熟練度」來保證開發人員實現的代碼符合設計人員的意圖。這樣即便在開發階段作到符合設計需求,也很難保證往後維護人員可以繼續貫徹原有的設計思想;隨着開發的時間愈來愈長,系統最終實現的樣子可能和原有的設計產生愈來愈大的誤差。在軟件工程中,將這種現象稱爲「架構腐化」。架構的「自約束能力」就是指限定不一樣開發人員在實現功能的時候,實現方式都是一致的,最好只有惟一一條遵循設計意願的路可走,別的方法沒法達到目的。更通俗地說就是,儘量使程序員不寫出爛代碼。
舉個最淺顯的例子,若是有開發人員在Web層中使用DAO直接操做數據庫,或者在DAL層直接從HttpSession對象中取上下文信息,這樣的代碼也許能逃過測試人員的黑盒測試,可是顯然是不符合軟件開發基本理論的。前者可能因繞過Service層中的事務配置而出現數據安全問題;後者限制了這樣的DAO就只能從Web訪問,沒法重用和進行單元測試。若是項目中出現這樣的代碼,筆者認爲首要責任在架構師,由於架構師沒有把各層的依賴分清,若是Web層只依賴Service層的JAR包,那麼程序員就沒法訪問到DAO,若是DAL層沒有依賴Servlet API的JAR包,那麼程序員就不可能訪問HttpSession對象,這就是一種架構缺少自約束能力的表現。
大概沒有哪一個架構師會犯上面例子那樣幼稚的錯誤。可是,實際狀況也遠比例子中的複雜,甚至有一些問題是Java語言自己的缺陷帶來的,例如,依賴了一個JAR包就意味着可以訪問這個JAR包中的一切類和資源,由於JAR包中的內容沒有Public、Private和Protected之分,沒法限制用戶能訪問什麼、不能訪問什麼。更復雜的狀況是在引入了同一個JAR包的不一樣版本時怎麼辦?若是依賴包須要動態變化怎麼辦?使用OSGi一個很重要的目的就是彌補Java中資源精細劃分的缺陷,增強架構的自約束能力。
雖然OSGi起源於精小軟件佔多數的嵌入式領域,可是在Java SE/EE領域中,對於越龐大的系統,使用OSGi進行模塊化拆分就越能發揮出優點。在商業上已經有一些使用OSGi控制軟件複雜度增加、延緩架構腐化速度的成功案例,如Eclipse Marketplace,它已經擁有了上千個插件,插件的開發者來自全球各地,技術水平差別很大,插件實現的功能也各不相同,是OSGi讓這些插件基本遵循了統一的架構約束,而且通常不會由於某個插件的缺陷影響整個Eclipse的質量。
1.2.2 OSGi能讓系統變得更穩定嗎
筆者遇到過許多由OSGi框架引起的問題,例如,最典型的ClassNotFoundException異常、類加載器死鎖或者在動態環境下的OutOfMemoryError問題等,這些都是基於OSGi架構開發軟件時很常見的。從這一方面看,使用OSGi確實會增長系統不穩定的風險,因此,在開發過程當中團隊中有一兩個深刻了解OSGi的成員是必要的。
不過,軟件是否穩定不是隻看開發階段可能出現多少異常就能衡量的,軟件的「穩定」應是多方面共同做用的結果。除了關注開發階段是否穩定以外,還要關注是否能積累重用穩定的代碼,問題出現時可否隔斷連鎖反應蔓延,缺陷是否容易修復等。在這些方面,OSGi就能夠帶來至關多的好處,例如:
- OSGi會引導程序員開發出可積累可重用的軟件。咱們沒法要求程序剛開發出來就是徹底穩定的,但能夠在開發過程當中儘量重用已穩定的代碼來提高程序質量。你們知道,寫日誌能夠使用Log4j,作ORM會引入Hibernate,Java中有許多通過長期實踐檢驗的、被證明爲穩定的開源項目,這些開源項目的共同特徵是都通過良好的設計,可以很方便地在其餘項目中使用。相對而言,在本身開發項目時不少人沒有注意到要進行可積累的設計。一種典型現象是項目中出現一些「萬能的包」,一般名字會是XXXCommons.jar、XXXUtils.jar等,這些包中存放了在項目中被屢次調用的代碼,可是這樣的包不能叫作可重用包。當這些包愈來愈大、類愈來愈多、功能愈來愈強時,與這個項目的耦合就越緊密,通常也就沒法用在其餘項目中了。在OSGi環境下,「大雜燴」形式的模塊是很難生存的,若是某個模塊有很是多的依賴項,那麼沒有人願意爲了使用其中少許功能去承擔這些間接依賴的代價。所以設計者必須把模塊設計得粒度合理,精心挑選對外發布的接口和引入的依賴,把每一個模塊視爲一個商業產品來對待,這樣才能積累出可重用的模塊,也利於提升程序穩定性。
- 基於OSGi比較容易實現強魯棒性的系統。普通汽車壞掉一個輪胎就會拋錨,可是飛機在飛行過程當中即便壞了其中一個引擎,通常都還能保持正常飛行。對於軟件系統來講,若是某一個模塊出了問題,可以不波及其餘功能的運做,這也是穩定性的一種體現。大多數系統都作不到在某部分出現問題時隔離缺陷帶來的連鎖反應。試想一下,在本身作過的項目中把Common Logging(或slf4j)的包拿掉,系統能只損失日誌功能而其餘部分正常運做嗎?可是對於基於OSGi架構開發系統,在設計時天然會考慮到模塊自治和動態化,當某部分不可用時如何處理是每時每刻都會考慮的問題,若是軟件在開發階段跟隨着OSGi的設計原則來進行,天然而然會實現強魯棒性的系統。
- 在OSGi環境下能夠作到動態修復缺陷。許多系統都有停機限制,要求7×24小時運行,對於這類系統,OSGi的動態化能力在出現問題時就很是有用,能夠作到不停機地增長或禁止某項功能、更新某個模塊,甚至創建一個統一更新的模塊倉庫,讓系統在不中斷運行的狀況下作到自動更新升級。
1.2.1節和1.2.2節提出的兩個問題能夠總結爲OSGi是否能提高開發效率和軟件質量。OSGi在這兩方面的做用與軟件設計得是否合理關係很是密切,這時OSGi比如一個針對「設計」這個因素的放大槓桿,配合好的設計它會更加穩定、高效,而遇到壞的設計,反而會帶來更多問題。
1.2.3 OSGi能讓系統運行得更快嗎
系統引入OSGi的目的可能有不少種,但通常不包括解決性能問題。若是硬要說OSGi對性能有什麼好處,大概就是讓那些有「系統潔癖」的用戶能夠組裝出爲本身定製的系統了。例如GlassFish v3.0服務器是基於OSGi架構的,它由200多個模塊構成,若是不須要EJB或JMS這類功能,就能夠把對應的模塊移除掉,以得到一個更精簡的服務器,節省一些內存。整體上講,OSGi框架對系統性能是有必定損耗的,咱們從執行和內存兩方面來討論。
首先,OSGi是在Java虛擬機之上實現的,它沒有要求虛擬機的支持,徹底經過Java代碼實現模塊化,在執行上不可避免地會有一些損耗。例如,OSGi類加載的層次比普通Java應用要深不少,這意味着須要通過更屢次的類加載委派才能找到所需的類。在兩個互相依賴的模塊間發生調用時,可能會因爲類加載器互相鎖定而產生死鎖;要避免死鎖的出現,有時候不得不選用有性能損失的串行化的加載策略。在服務層上,動態性(表現爲服務可能隨時不可用)決定了應用不能緩存服務對象,必須在每次使用前查找,這種對OSGi服務註冊表的頻繁訪問也會帶來一些開銷。使用一些具體的OSGi服務,例如使用HTTP Service與直接部署在Web容器中的Servlet相比會因爲請求的橋接和轉發產生一些性能損耗。
其次,從內存用量來看,OSGi容許不一樣版本的Package同時存在,這是個優勢,可是客觀上會佔用更多內存。例如,一個庫可能須要 ASM 3.0,而同一應用程序使用的另外一個庫可能須要ASM 2.0,要解決這種問題,一般須要更改代碼,而在OSGi中只須要付出一點Java方法區的內存便可解決。不過,若是對OSGi動態性使用不當,可能會由於不正確持有某個過時模塊(被更新或卸載的模塊)中一個類的實例,致使該類的類加載器沒法被回收,進而致使該類加載器下全部類都沒法被GC回收掉。
僅從性能角度來講,OSGi確實會讓系統性能略微降低,可是這徹底在可接受範圍以內。使用OSGi開發時應該考慮到性能的影響,但不該當將其做爲是否採用OSGi架構的主要決策依據。
1.2.4 OSGi能支撐企業級開發嗎
無論關於「OSGi是否能支撐企業級開發」的討論結果如何,一個必須正視的事實是OSGi對企業級開發的支撐能力正在迅速加強。從2007年OSGi聯盟創建企業專家組以來,OSGi的發展方向已經逐漸調整到企業級應用領域。在IBM、Apache和Eclipse基金會等公司和組織推進下,企業級OSGi正在變得愈來愈成熟。
在企業級OSGi出現以前,企業級開發要麼是走Java EE的重量級路線,要麼是走SSH的輕量級路線。企業級OSGi被引入後並無扮演一個「革命者」的角色,沒有把Java EE或SSH中積累的東西推倒重來,OSGi更像是在扮演一個「組織者」的角色,把各類企業級技術變爲它的模塊和服務,使之前的企業級開發技術在OSGi中依然可以發揮做用。
OSGi企業級規範中定義了JDBC、JPA、JMX、JTA和JNDI等各類Java EE技術以及SCA、SDO這些非Java EE標準的企業級技術在OSGi環境中的應用方式,這些容器級的服務均可以映射爲OSGi容器內部的服務來使用。而且到如今,企業級規範定義的內容已經不只停留在規範文字中,已經有很多專一於OSGi企業級服務實現框架出現(例如Apache Aries)了。
另外一方面,OSGi的Blueprint容器規範統一了Java大型程序中幾乎都會用到的依賴注入(DI)方式,使基於Blueprint的OSGi模塊能夠在不一樣的DI框架中無縫遷移。這個規範獲得Apache、SpringSource等組織的大力支持,目前這些組織已經發布了若干個Blueprint規範的實現容器(例如Apache Geronimo和Equinox Virgo,Virgo前身就是SpringSource捐獻的Spring DM 2.0)。在最近兩三年時間裏,企業級OSGi成爲Java社區技術發展的主要方向之一,其發展局面能夠說是如火如荼。
不過,咱們在使用企業級OSGi的時候也要意識到它還很年輕,其中不少先進的思想多是遺留程序根本沒有考慮過的,還有很多問題的解決都依賴於設計約束來實現。所以,若是是遺留系統的遷移,或者設計原本就作得很差,那麼使用OSGi會遇到很多麻煩。以最多見的數據訪問爲例,若是之前遺留系統使用了ORM方式訪問數據庫,而遷移到OSGi時沒有把實體類統一抽取到一個模塊,那麼ORM模塊的依賴就很難配置了,這時不得不使用Equinox Buddy甚至DynamicImport-Package這類很不優雅的方式來解決。另外一個問題是集羣,OSGi擁有支持分佈式的遠程服務規範,而OSGi的動態性是針對單Java虛擬機實例而言的,所以要在集羣環境下保持OSGi的動態性,就必須本身作一些工做才行。
1.3 本章小結
在本書中,筆者嘗試闡述與OSGi相關的三個問題:什麼是OSGi?爲何要使用OSGi?以及如何使用OSGi?在本章中,咱們已經解答了前兩個問題,本書後面的13章都將圍繞「如何使用OSGi」這個問題來進行,經過研讀OSGi核心規範、分析最經常使用的OSGi實現框架Equinox以及與讀者一塊兒經過實踐來了解如何使用OSGi技術開發程序。
原網址:http://osgi.com.cn/article/7289372
本文由OSGi China提供 轉載請註明來源