日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
OSGi全面總結(jié)與WebSphere應(yīng)用范例

本文是IBMDW的王志強(qiáng)撰寫(xiě)的文章,原文名稱(chēng)為《實(shí)現(xiàn) WebSphere Application Server 上應(yīng)用程序?qū)?OSGi 的支持》。

目前創(chuàng)新互聯(lián)已為近千家的企業(yè)提供了網(wǎng)站建設(shè)、域名、虛擬空間、網(wǎng)站運(yùn)營(yíng)、企業(yè)網(wǎng)站設(shè)計(jì)、宜陽(yáng)網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶(hù)導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶(hù)和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。

編輯推薦:OSGi入門(mén)與實(shí)踐全攻略

為了解決現(xiàn)實(shí)工程中遇到的版本沖突問(wèn)題,我研究了 OSGi 技術(shù)。為此,我在網(wǎng)上搜索了很多的有關(guān)于 OSGi 的文章,但是最后發(fā)現(xiàn)很少有人能清楚的闡述 OSGi 的由來(lái)和 OSGi 最本質(zhì)的特性,直到我發(fā)現(xiàn) Neil Bartlett 的 OSGi In Practice。它讓理解了 OSGi 的本質(zhì),從而清楚的明白:解決 Java 工程中的版本沖突問(wèn)題,OSGi 是最好的選擇。這是由 OSGi 的本質(zhì)決定的,這也是為什么大的 Java 軟件產(chǎn)品紛紛開(kāi)始采用 OSGi 框架的原因。Java 有天生的缺陷,而 OSGi 彌補(bǔ)了它。然后我又花了大量的時(shí)間來(lái)研究 WebSphere Application Server 是如何支持 OSGi 的,最后才能成功的使我的應(yīng)用支持 OSGi,從而解決了版本沖突問(wèn)題。但這一整個(gè)過(guò)程耗費(fèi)了我大量的時(shí)間和精力,為了能讓遇到同樣問(wèn)題的人少走彎路,我寫(xiě)了這篇文章,希望能夠有所幫助。

OSGi 的由來(lái)

隨著科技和需求的發(fā)展和變化,現(xiàn)在的軟件變得越來(lái)越龐大。這樣,隨之而來(lái)的最大挑戰(zhàn)就是軟件在設(shè)計(jì)上的越來(lái)越復(fù)雜和維護(hù)上的越來(lái)越困難。為了解決這個(gè)問(wèn)題,軟件架構(gòu)師將軟件切分成比較小的并且易于理解的多個(gè)模塊。那么軟件模塊化會(huì)給我們帶來(lái)什么樣的好處呢?

  • 拆分人力:將軟件模塊化后,我們就可以分配獨(dú)立的團(tuán)隊(duì)去處理獨(dú)立的模塊,從而將人力拆分開(kāi)來(lái)。這樣既便于管理,又會(huì)降低整個(gè)軟件的設(shè)計(jì)的復(fù)雜性。因?yàn)槊總€(gè)獨(dú)立的團(tuán)隊(duì)可以專(zhuān)心去設(shè)計(jì)和實(shí)現(xiàn)其模塊,而不用通盤(pán)考慮整個(gè)軟件的復(fù)雜性。
  • 抽象化:將軟件模塊化后,我們將整個(gè)軟件抽象化成多層、多 模塊的一個(gè)集成。這樣使整個(gè)軟件易于理解,便于管理。
  • 重用:將軟件模塊化后,每個(gè)模塊有其獨(dú)立的功能和封裝。這樣這個(gè)模塊就可以在多處(甚至是將來(lái)其他的軟件中)重用,從而節(jié)省人力。
  • 易于維護(hù):將軟件模塊化后,當(dāng)軟件出現(xiàn)問(wèn)題后,我們可以容易地定位問(wèn)題出在那個(gè)模塊,而每個(gè)模塊又相對(duì)較小和易于理解,從而降低了軟件維護(hù)的難度。

基于上述的 4 個(gè)優(yōu)點(diǎn),在當(dāng)前的軟件設(shè)計(jì)中,軟件模塊化是軟件架構(gòu)師的主流思想。為了實(shí)現(xiàn)軟件模塊化,應(yīng)運(yùn)而生的就是面向?qū)ο蟮母呒?jí)編程語(yǔ)言,Java 是其中的典型代表。Java 用其獨(dú)有的 Jar 格式文件去包裝 Java 類(lèi)和其他的資源文件,從而可以將軟件組件封裝成獨(dú)立的 Jar 文件。這些 Jar 文件可以相互依賴(lài)并共同完成同一個(gè)工作,從而實(shí)現(xiàn)了軟件的模塊化。但是 Java 卻不能真正的帶給我們軟件模塊化的那 4 個(gè)優(yōu)點(diǎn),為什么呢?為了解釋這個(gè)問(wèn)題,我們需要知道模塊的定義。

什么是一個(gè)模塊?

一個(gè)模塊應(yīng)該有以下 3 個(gè)特性:

  • 自包含:一個(gè)模塊應(yīng)該是一個(gè)業(yè)務(wù)邏輯的整體。它應(yīng)該可以作為一個(gè)獨(dú)立的整體被移動(dòng)、安裝和卸載。模塊不是一個(gè)原子體,它可以包含多個(gè)更小的部分,但這些部分不能獨(dú)立存在。
  • 高內(nèi)聚:一個(gè)模塊不應(yīng)該做很多不相關(guān)的事情,它應(yīng)該專(zhuān)注于 1 個(gè)業(yè)務(wù)邏輯的目標(biāo)并盡全力實(shí)現(xiàn)這個(gè)目標(biāo)。
  • 低耦合:一個(gè)模塊不應(yīng)該關(guān)注其他模塊的內(nèi)部實(shí)現(xiàn),松散的聯(lián)系允許我們?nèi)ジ哪硞€(gè)特定的模塊,而不會(huì)影響到其他的模塊。

而 Java 語(yǔ)言的 Jar 文件并不能完美的實(shí)現(xiàn)一個(gè)模塊這 3 個(gè)特性,它主要會(huì)遇到以下的 3 個(gè)問(wèn)題:

  1. 針對(duì)一個(gè) Jar 文件,沒(méi)有對(duì)應(yīng)的 Java 運(yùn)行時(shí)的概念。Jar 文件只有在開(kāi)發(fā)和部署的時(shí)候有意義,而在 JVM 中,所有的 Jar 文件中的內(nèi)容被簡(jiǎn)單地聯(lián)系在一起作為一個(gè)單獨(dú)的全局的列表,這就是所謂的“Classpath”。這種類(lèi)加載模式,使 Jar 文件在運(yùn)行時(shí)是不可見(jiàn)的。
  2. Jar 文件沒(méi)有標(biāo)準(zhǔn)的元數(shù)據(jù)信息去指明該 Jar 文件所需要的外部依賴(lài)文件列表,這樣我們就不能清楚的知道,該 Jar 文件需要和其他的那些 Jar 文件一起工作。另外,現(xiàn)在的 Jar 文件沒(méi)有版本信息,這樣,同一 Jar 文件的多個(gè)版本就不能同時(shí)被加載。
  3. Java 沒(méi)有機(jī)制在不同的 Jar 文件中隱藏信息。

這 3 個(gè)問(wèn)題,使 Jar 文件在模塊的“自包含”和“低耦合”這兩個(gè)特性上做的不好,從而使 Java 在模塊的“拆分人力”和“易于維護(hù)”這兩個(gè)優(yōu)點(diǎn)上沒(méi)有好的表現(xiàn),而更嚴(yán)重的是第 2 個(gè)問(wèn)題,這使 Java 應(yīng)用軟件存在難以處理的版本沖突問(wèn)題。

Java 語(yǔ)言為了安全的考慮,它的類(lèi)加載器(注意不是類(lèi)加載)是多層立體的并且對(duì)其類(lèi)加載采用了父委托機(jī)制。并且,當(dāng)同一個(gè)類(lèi)加載器加載類(lèi)文件時(shí),JVM 會(huì)加載最先發(fā)現(xiàn)類(lèi)。所以當(dāng)同一個(gè)類(lèi)的新舊兩個(gè)版本被分別封裝在兩個(gè)不同的 jar 文件中(比如:ClassVersion2.jar 和 ClassVersion1.jar),而這兩個(gè) jar 文件又都在 JVM 的類(lèi)加載路徑里的話,最先被加載的 Jar 文件中的類(lèi)才會(huì)被使用到。而現(xiàn)在的 Java 應(yīng)用軟件因?yàn)殚L(zhǎng)時(shí)間的更新維護(hù),同一個(gè)模塊的多個(gè)版本共存的情況比比皆是,這就會(huì)產(chǎn)生版本沖突問(wèn)題。比如說(shuō),在 Java 應(yīng)用軟件中存在一個(gè)模塊 ThirdComponent,這個(gè)模塊依賴(lài) ClassVersion 模塊而且必須同老版本的 ClassVersion 模塊(ClassVersion1.jar)一起工作,當(dāng)新 ClassVersion 模塊(ClassVersion2.jar)被升級(jí)到軟件中后,ThirdComponent 模塊很有可能就不會(huì)工作,因?yàn)轭?lèi)加載器很有可能會(huì)先加載的是 ClassVersion2.jar,而不是 ClassVersion1.jar。其實(shí)產(chǎn)生這個(gè)問(wèn)題的根本原因是,Java 的 Jar 文件在自包含上做的不好。Jar 文件只是在軟件的封裝上起到了作用,而在 JVM 運(yùn)行時(shí)中,Java 只關(guān)心類(lèi)而忽略了 Jar,從而使 Java 的類(lèi)加載變成了平面的線性的而非立體的網(wǎng)狀的。

為了解決 Java 在模塊化中存在的問(wèn)題,OSGi 模塊系統(tǒng)出現(xiàn)了。OSGi 是基于 Java 之上開(kāi)發(fā)的,它提供了一種建立模塊化的 Java 應(yīng)用程序的方法并定義了這些模塊在運(yùn)行時(shí)中如何相互交互。

OSGi 最本質(zhì)的特性

OSGi 是一個(gè)由大概 40 個(gè)公司組成的聯(lián)盟來(lái)共同定義的一個(gè)標(biāo)準(zhǔn)。依照這個(gè)標(biāo)準(zhǔn),目前,有 4 種獨(dú)立實(shí)現(xiàn)了的 OSGi 框架,他們分別是:

  • Equinox: 這個(gè) OSGi 框架是目前應(yīng)用最廣泛的 OSGi 框架。它是由 IBM 開(kāi)發(fā)的,目前已經(jīng)被應(yīng)用到 Eclipse,Lotus Notes,IBM WebSphere Application Server 等等。Equinox 實(shí)現(xiàn)了版本為 4.1 的 OSGi 規(guī)范。
  • Felix:這個(gè) OSGi 框架實(shí)現(xiàn)了版本 4.x 的 OSGi 規(guī)范,它是由 Apache 開(kāi)發(fā)和維護(hù)的。
  • Knopflerfish:這是一個(gè)流行并成熟的實(shí)現(xiàn)了版本 3 和 4.1 的 OSGi 規(guī)范的 OSGi 框架。它是由 Makewave AB 開(kāi)發(fā)和維護(hù)的。
  • Concierge:這個(gè) OSGi 框架實(shí)現(xiàn)了版本 3 的 OSGi 規(guī)范。

關(guān)于 OSGi 這個(gè)名字,2 個(gè)最常被問(wèn)到的問(wèn)題是 OSGi 代表什么?為什么 i 是小寫(xiě)的?

關(guān)于這兩個(gè)問(wèn)題,權(quán)威性的回答是:官方上 OSGi 不代表任何東西,然而,通常上說(shuō) OSGi 代表“Open Service Gateway initiative. 而小寫(xiě)字母“i”來(lái)自單詞“initiative”。

至于 OSGi 的中心思想,它非常地簡(jiǎn)單。傳統(tǒng) Java 軟件問(wèn)題的根源就是全局的扁平的類(lèi)加載路徑(Classpath),所以 OSGi 采用了一種完全不同的類(lèi)加載機(jī)制,那就是每個(gè)模塊都有其獨(dú)立的類(lèi)加載路徑。這幾乎解決了傳統(tǒng) Java 在模塊化中遇到的所有問(wèn)題,然而一個(gè)新的問(wèn)題又產(chǎn)生了,軟件中的模塊是要在一起工作的,這就意味著不同的模塊之間存在類(lèi)共享(不然的話,一個(gè)模塊如何能夠調(diào)用到另外一個(gè)模塊呢),如果每個(gè)模塊有一個(gè)類(lèi)加載路徑,模塊間的類(lèi)共享如何解決?為了解決這個(gè)問(wèn)題,OSGi 定義了一個(gè)特殊的并完善的類(lèi)共享機(jī)制。OSGi 將會(huì)采用顯示的導(dǎo)入和導(dǎo)出機(jī)制來(lái)控制模塊間的類(lèi)共享。

在 OSGi 中,模塊被起了另外一個(gè)名字,叫做 bundle。實(shí)際上 OSGi 的 bundle 就是一個(gè) Java 的 Jar 文件。OSGi 并沒(méi)有定義一個(gè)新的標(biāo)準(zhǔn)去封裝 Java 類(lèi)和其他的資源文件,標(biāo)準(zhǔn) Jar 文件可以很好地工作在 Java 應(yīng)用軟件中。在 OSGi 體系里,只是一些新的元數(shù)據(jù)信息被加入到 Jar 文件中,這些元數(shù)據(jù)信息使的 Jar 文件變成一個(gè) OSGi 體系中的 bundle。那么什么樣的元數(shù)據(jù)信息被加入進(jìn)來(lái)了呢?

  1. Bundle 的名字。OSGi 提供了一個(gè)“symbolic”名字作為這個(gè) bundle 的唯一標(biāo)識(shí)符。
  2. Bundle 的版本信息。
  3. Import 和 export 列表。從這個(gè)列表,我們可以清楚地知道這個(gè) OSGi bundle 需要導(dǎo)入和導(dǎo)出那些包的類(lèi)。導(dǎo)入的包是本 bundle 需要用到的外部資源,導(dǎo)出的包是其他 bundle 可以用的本 bundle 中的資源。
  4. Bundle 需要運(yùn)行的最小的 Java 版本。這個(gè)信息是可選的。
  5. 種類(lèi)繁雜的人類(lèi)可讀的其他信息,比如說(shuō):本 bundle 的提供者,版權(quán)陳述,聯(lián)系地址等等。

這些元數(shù)據(jù)信息被放到 Jar 文件的 MANIFEST.MF 文件中,而這個(gè)文件是每個(gè)標(biāo)準(zhǔn) Jar 文件的一部分。用一個(gè)標(biāo)準(zhǔn)的 Jar 文件作為 OSGi bundle 的一個(gè)好處是 bundle 可以被用在 Jar 文件可以出現(xiàn)的任何一個(gè)地方,因?yàn)?bundle 就是一個(gè)純粹的 Jar 文件。當(dāng)一個(gè) bundle 用在 OSGi 的運(yùn)行時(shí)之外的時(shí)候,這些額外多出來(lái)的元數(shù)據(jù)信息會(huì)被 Java 運(yùn)行時(shí)簡(jiǎn)單地忽略掉,所以說(shuō),bundle 是向前兼容的。那么除了這個(gè),OSGi 的 bundle 還給我們帶來(lái)了什么樣的好處呢?

為每一個(gè) bundle 提供一個(gè)類(lèi)加載路徑意味著什么呢?簡(jiǎn)單地說(shuō)我們?yōu)槊恳粋€(gè) bundle 提供了一個(gè)類(lèi)加載器,這個(gè)類(lèi)加載器能夠看到這個(gè) bundle 文件里的類(lèi)和其他資源文件。但是為了達(dá)到多個(gè) bundle 共同工作的目的,在 OSGi 的類(lèi)加載器之間,類(lèi)加載請(qǐng)求可以從一個(gè) bundle 的類(lèi)加載器被委托到另外一個(gè) bundle 的類(lèi)加載器?;叵胍幌略跇?biāo)準(zhǔn) Java 和 J2EE 中,類(lèi)加載器是一個(gè)樹(shù)形結(jié)構(gòu)的,類(lèi)加載請(qǐng)求總是被向上委托給每一個(gè)類(lèi)加載器的父親。這中類(lèi)加載機(jī)制不允許在水平的樹(shù)節(jié)點(diǎn)之間進(jìn)行類(lèi)加載委托。為了讓一個(gè)類(lèi)庫(kù)可以被類(lèi)加載器樹(shù)的多個(gè)樹(shù)枝共同所見(jiàn),我們就需要將這個(gè)類(lèi)庫(kù)推到這些樹(shù)枝共同的祖先節(jié)點(diǎn)。這樣這個(gè)版本的類(lèi)庫(kù)就會(huì)被這些樹(shù)枝上的所有節(jié)點(diǎn)所見(jiàn),而不管是否這些節(jié)點(diǎn)都想看到這個(gè)版本的類(lèi)庫(kù)。圖 1 是一個(gè)典型的 J2EE 類(lèi)加載器層次結(jié)構(gòu),它展示了為什么類(lèi)庫(kù)會(huì)不斷推高的原因。

圖 1. 典型的 J2EE 類(lèi)加載器層次結(jié)構(gòu)

而樹(shù)型結(jié)構(gòu)并不是我們需要的,我們真正需要的是網(wǎng)狀結(jié)構(gòu)。兩個(gè)組件之間的依賴(lài)關(guān)系不是簡(jiǎn)單的上下級(jí)的關(guān)系,而應(yīng)該是一種提供者和使用者的網(wǎng)絡(luò)關(guān)系。類(lèi)的加載請(qǐng)求被從一個(gè) bundle 的類(lèi)加載器委托到另外一個(gè) bundle 的類(lèi)加載器,而這種委托是基于 bundle 之間的這種網(wǎng)狀的依賴(lài)關(guān)系。圖 2 給了我們一個(gè) OSGi 中 bundle 之間的網(wǎng)狀的依賴(lài)關(guān)系的例子。

圖 2. OSGi 中 bundle 之間的網(wǎng)狀的依賴(lài)關(guān)系

在 OSGi 中,bundle 之間的依賴(lài)關(guān)系是通過(guò)顯示的 import 和 export 類(lèi)包列表來(lái)決定的。比如說(shuō),在圖 2 的 bundle B 中包含一個(gè)類(lèi)包,名字為 com.ibm.bundle.b.somePackage.。Bundle b 就可以選擇在它的 MANIFEST.MF 文件去 export 這個(gè)類(lèi)包。而 bundle A 也可以選擇去在它的 MANIFEST.MF 文件中 import 類(lèi)包 com.ibm.bundle.b.somePackage。然后在 OSGi 運(yùn)行時(shí)中,OSGi 框架將負(fù)責(zé)匹配不同 bundle 的 import 和 export 列表。而這個(gè)匹配過(guò)程被稱(chēng)為 OSGi 的解決過(guò)程(resolution process)。OSGi 的解決過(guò)程是相當(dāng)復(fù)雜的,但是這個(gè)過(guò)程是被 OSGi 框架實(shí)現(xiàn)了的,不需要每個(gè) bundle 自己來(lái)關(guān)心它。每個(gè) bundle 只需要寫(xiě)一些很簡(jiǎn)單的 import 和 export 聲明語(yǔ)句在各自的 MANIFEST.MF 文件里。一旦 OSGi 框架匹配了 bundle A 的 import 列表里的類(lèi)包 com.ibm.bundle.b.somePackage 與 bundle B 的 export 列表里的類(lèi)包 com.ibm.bundle.b.somePackage,那么這兩個(gè) bundle 就會(huì)被連接在一起,而這就意味著當(dāng) bundle A 需要載入任何類(lèi)包 com.ibm.bundle.b.somePackage 里的類(lèi)時(shí),這個(gè)類(lèi)載入請(qǐng)求就會(huì)被委托給 bundle B 的類(lèi)載入器,而 bundle B 的類(lèi)載入器將會(huì)載入這個(gè)類(lèi),并將類(lèi)實(shí)例傳給 bundle A。而因?yàn)?bundle A 依賴(lài) bundle B 和 bundle C, 如果 bundle A import 列表里的所有類(lèi)包都能在 bundle B 和 bundle C 的 export 列表里發(fā)現(xiàn),那么 bundle A 將會(huì)被稱(chēng)為解決成功,它會(huì)進(jìn)入解決了狀態(tài)(resolved)。如果 bundle A 的 import 列表里需要的某些類(lèi)包沒(méi)有在 bundle B 和 bundle C 的 export 列表里發(fā)現(xiàn),那么 bundle A 的解決就沒(méi)有成功,bundle A 將不能被使用和啟動(dòng)。由此可見(jiàn),OSGi 中,bundle 之間的依賴(lài)關(guān)系是通過(guò)顯示的 import 和 export 列表來(lái)決定的。

  1. 隱藏了 bundle 中的信息。

    因?yàn)樵?OSGi 中,bundle 之間的依賴(lài)關(guān)系是通過(guò)顯示的 import 和 export 列表來(lái)決定的,所以我們沒(méi)有必要 export 一個(gè) bundle 中的所有的類(lèi)包,進(jìn)而能起到隱藏 bundle 中信息的作用。在 OSGi 中,只有那些被顯示的 export 出來(lái)的類(lèi)包才能被其他的 bundle import。

  2. 增加了版本控制并允許多版本并存。

    OSGi 不僅僅使 bundle 之間通過(guò)類(lèi)包名相互依賴(lài),它還可以為類(lèi)包加入版本信息。這是我們能夠應(yīng)付 bundle 的版本變化問(wèn)題。Export 的類(lèi)包也可以攜帶一個(gè)版本信息,而 import 卻可以引用一個(gè)版本范圍內(nèi)的所有類(lèi)包,這讓我們的 bundle 可以依賴(lài)一個(gè)版本范圍內(nèi)的所有類(lèi)包。于是說(shuō),在 OSGi 中,同一 bundle 的多個(gè)版本就可以同時(shí)存在。在本文的第三章,我將詳細(xì)介紹,OSGi 是如何允許同一個(gè) bundle 的多個(gè)版本并行存在,進(jìn)而客服了 Java 應(yīng)用軟件中組件的版本沖突問(wèn)題

解釋 OSGi 是如果克服版本沖突問(wèn)題的

OSGi 之所以能夠解決 Java 應(yīng)用軟件中組件的版本沖突問(wèn)題,原因就是 OSGi 的網(wǎng)狀類(lèi)加載器和 OSGi bundle 的版本信息控制。為什么這么說(shuō)呢?

  1. OSGi 的網(wǎng)狀類(lèi)加載器架構(gòu)使每個(gè) OSGi bundle 都擁有一個(gè)獨(dú)立的類(lèi)加載器,而 bundle 只是一個(gè)標(biāo)準(zhǔn) Jar 文件。這樣,對(duì)同一個(gè) bundle 的不同版本,我們就可以創(chuàng)建多個(gè)不同的 Jar 文件。這些 Jar 文件的實(shí)際內(nèi)容可以完全一樣,而只是文件名不同(甚至文件名都可以相同,因?yàn)樵?OSGi 框架中,bundle 名和版本的組合才是唯一標(biāo)識(shí)符)。因此這些 Jar 文件,在 OSGi 框架看來(lái),是不同的 bundle,于是同一個(gè)組件的不同版本可以被同時(shí)載入到 JVM 中,這就解決了 Java 應(yīng)用軟件中同一組件不同版本的并存問(wèn)題,接下來(lái)只要解決版本辨識(shí)問(wèn)題,那么 Java 應(yīng)用軟件中組件的版本沖突問(wèn)題就會(huì)被客服掉了。
  2. OSGi 添加了版本控制信息來(lái)區(qū)分同一個(gè) bundle 的不同版本,而且在 OSGi 框架中 bundle 名和 bundle 版本的組合才是這個(gè) bundle 的唯一標(biāo)識(shí)符,于是通過(guò) bundle 的版本控制,同一個(gè) bundle 的不同版本就可以得到區(qū)分,而 bundle 直接的依賴(lài)關(guān)系也可以通過(guò)版本來(lái)加以限制,從而就能完美的解決 Java 應(yīng)用軟件中組件的版本沖突問(wèn)題了。

那么 OSGi 是如何進(jìn)行版本控制的呢?

OSGi 通過(guò)在 MANIFEST.MF 文件中添加 Bundle-Version 屬性來(lái)個(gè)為每一個(gè) bundle 添加一個(gè)版本信息,而且這個(gè)版本信息必須嚴(yán)格遵循:3 數(shù)字段 +1 字符段的格式,6.2.0.beta_3 是一個(gè)典型有效的 bundle 版本信息。這前面的 3 個(gè)數(shù)字段就是大家都知道的主版本,小版本和微版本,而那個(gè)最后的字母段則是校正段。當(dāng)前面的 3 個(gè)任意一個(gè)數(shù)字段沒(méi)有值時(shí),OSGi 將會(huì)隱式地將 0 付給這個(gè)字段,所以版本 1 是和 1.0、1.0.0 相同的。而如果沒(méi)給 bundle 指定任意一個(gè)版本,那么 0.0.0 將被認(rèn)為是這個(gè) bundle 的版本信息。

另外 OSGi 中,版本的比較是采用從前到后的比較方式。如果在版本比較時(shí),第一個(gè)數(shù)字段就不同,那么后面的 3 個(gè)字段就不用比較了,因?yàn)?OSGi 的前一個(gè)版本段是后面所有字段值的總和,所以大版本就不相同的時(shí)候,后面的小版本就不需要比較了,比如說(shuō):2.0.0 是大于 1.999.999。而如果兩個(gè) bundle 的版本信息,在前面的 3 個(gè)數(shù)字段都相同的時(shí)候,OSGi 就會(huì)對(duì)最后的字母段進(jìn)行比較。而最后的字母段可以包含大寫(xiě)或小寫(xiě)的字母 A 到 Z、數(shù)字、連接線和下劃線,所以它的比較比較復(fù)雜。OSGi 采用了標(biāo)準(zhǔn) Java String 類(lèi)的 compareTo() 方法的算法來(lái)進(jìn)行比較,而標(biāo)準(zhǔn) Java 的 String 類(lèi)的 compareTo() 方法會(huì)對(duì)校正段的每一個(gè)字母按順序進(jìn)行比較,直到出現(xiàn)差異。另外如果字母相同,那么短的那個(gè)校正段的值將被認(rèn)為小于長(zhǎng)的校正段,beta_01 將會(huì)比 beta_010 小。

最后需要提的是 OSGi 不但可以為 bundle 指定一個(gè)版本信息,還可以為每一個(gè)類(lèi)包指定一個(gè)版本信息,即 bundle 的版本控制是可以做到類(lèi)包級(jí)別的(而且這是推薦的 OSGi 版本控制方式)。當(dāng) bundle 在 export 類(lèi)包時(shí),用戶(hù)可以為每個(gè)類(lèi)包指定一個(gè)版本信息。而當(dāng) bundle 需要 import 某特定版本的類(lèi)包時(shí),用戶(hù)除了可以指定一個(gè)特定的版本信息外,還可以指定一個(gè)版本信息范圍。而這個(gè)范圍可以用方括號(hào)“【”和圓括號(hào)“(”來(lái)作為邊界,方括號(hào)“【”表示邊界值也在范圍之內(nèi),而圓括號(hào)“(”則相反 . 比如說(shuō)【 1.0.0,2.0.0)表示從版本 1.0.0 開(kāi)始到 2.0.0 之間的所有的小版本,2.0.0 不在這個(gè)范圍只內(nèi)。下面是一些進(jìn)一步的范圍列表的例子,在下面的表 1 中 x 代表有效的范圍列表:

表 1. 版本范圍舉例

樣例 版本范圍
[1.2.3,4.5.6)1.2.3<=x<4.5.6
[1.2.3,4.5.6]1.2.3<=x<=4.5.6
(1.2.3,4.5.6)1.2.3
(1.2.3,4.5.6]1.2.3
[1.2.3,1.2.3]1.2.3
1.2.31.2.3<=x
 0.0.0<=x

解釋 WAS 在引入 OSGi 之后的類(lèi)載入機(jī)制

OSGi 是如此優(yōu)秀的一個(gè)框架,因此很多 Java 應(yīng)用軟件開(kāi)始采用它,WebSphere Application Server(WAS)作為 IBM 最中要的 J2EE 服務(wù)器從版本 6.1 開(kāi)始采用 OSGi 框架,因此當(dāng)你的應(yīng)用是基于 WAS 的并遇到了版本沖突問(wèn)題,你就可以將你的應(yīng)用轉(zhuǎn)換成 OSGi 的 bundle,從而解決版本沖突問(wèn)題。在將你的 WAS 的應(yīng)用轉(zhuǎn)變成 OSGi 的 bundle 之前,我們需要了解 WAS 是如何支持 OSGi 的,進(jìn)而采取相應(yīng)的行動(dòng)。

圖 3. WAS 從 6.1 以后的類(lèi)加載器層次結(jié)構(gòu)

圖 3 是 WAS 從版本 6.1 以后的類(lèi)加載器層次結(jié)構(gòu),從此圖,我們可以知道 WAS 并不是完全采用 OSGi 框架(可能是出于向前兼容等因素考慮),IBM 只是將 WAS 的一部分變成了 OSGi 框架的類(lèi)加載模式,而其他的部分繼續(xù)延續(xù)了以前版本的類(lèi)加載器層 次結(jié)構(gòu)。而 WAS 中 OSGi 的那部分類(lèi)加載器,以網(wǎng)關(guān)的形式與 WAS 的擴(kuò)展類(lèi)加載器連接在一起。

接下來(lái),大家可能奇怪,WAS 原有的類(lèi)加載器是如何同 WAS 中的 OSGi 部分的類(lèi)加載器一起工作的呢? WAS 將如何進(jìn)行類(lèi)加載呢?

為了解釋這個(gè)問(wèn)題,我們首先要清楚,WAS 中的那一部分采用了 OSGi 的框架? WAS 將其常用的重要的插件部分做成了 OSGi,而所有的這些插件被放置在 WAS 的 plugins 目錄中,因此 plugins 目錄下的所有的插件是以 OSGi bundle 的形式被載入到 WAS 中來(lái)的。接下來(lái),我將解釋從版本 6.1 以后 WAS 將如何進(jìn)行類(lèi)加載。從圖 3,我們可以得知,WAS 的 OSGi 框架是與 Ext 類(lèi)加載器連接在一起的,這就是說(shuō) WAS 的 OSGi 框架在 WAS 整體的類(lèi)加載器中處于一個(gè)很高的層次。而 Java 的類(lèi)加載是采用父委托機(jī)制的,這就使普通的 WAS 上的應(yīng)用程序會(huì)一層層的向上請(qǐng)求加載類(lèi),這樣當(dāng)某個(gè)特定的類(lèi)在 WAS 的 OSGi 部分中被發(fā)現(xiàn),那么 WAS 的類(lèi)加載委托就會(huì)進(jìn)入到 WAS 的 OSGi 運(yùn)行時(shí)中。這樣當(dāng)這個(gè)類(lèi)加載以后,而它又需要加載其他類(lèi)時(shí),這之后的類(lèi)加載委托請(qǐng)求就會(huì)在 WAS 的 OSGi 運(yùn)行時(shí)中相互傳遞。

由此可見(jiàn),如果我們需要將自己的 WAS 上的應(yīng)用程序轉(zhuǎn)變成支持 OSGi,我們則需要將這個(gè)應(yīng)用程序的模塊轉(zhuǎn)變成 OSGi bundle,然后將其放置在 WAS 的 plugins 目錄下。

介紹一個(gè)具有版本沖突問(wèn)題的 WAS 上的樣例程序

在本章,我會(huì)模擬一個(gè) WAS 上版本沖突的問(wèn)題,讓大家能清楚地看到這種版本沖突問(wèn)題是如何出現(xiàn)的。然后在第六章,我會(huì)告訴大家如何將這個(gè)樣例程序的某些組件轉(zhuǎn)變成 bundle,從而解決了版本沖突問(wèn)題。

為了說(shuō)明問(wèn)題,我構(gòu)建如下一個(gè)郵件系統(tǒng),這個(gè)系統(tǒng)可以閱讀各種各樣類(lèi)型的郵件。因?yàn)猷]件的類(lèi)型可以存在很多種,而且每一種的郵件可以使用獨(dú)特的瀏覽方式,為了設(shè)計(jì)和維護(hù)的簡(jiǎn)單,我們將它拆分成多個(gè)模塊。我們將各種郵件類(lèi)型共用的接口和基礎(chǔ)類(lèi)拆分成一個(gè)模塊,而將每種不同的郵件類(lèi)型拆分成各自獨(dú)立的模塊。而為了便于描述將來(lái)會(huì)出現(xiàn)的版本沖突問(wèn)題,我們只是用兩種簡(jiǎn)單的硬編碼的郵件類(lèi)型(FixedMailbox 和 XMLMailbox)來(lái)說(shuō)明這個(gè)系統(tǒng)的整體結(jié)構(gòu),請(qǐng)看圖 4。

圖 4. 郵件系統(tǒng)結(jié)構(gòu)圖

這個(gè)結(jié)構(gòu)圖能夠清晰得告訴我們,整個(gè)系統(tǒng)的通用接口和基礎(chǔ)類(lèi)被封裝在 MailboxAPI 模塊中,而每個(gè)具體的郵件類(lèi)型將分別是一個(gè)模塊(FixedMailbox 模塊和 XMLMailbox 模塊),這些模塊將實(shí)現(xiàn)這些通用接口和每種郵件類(lèi)型各自的業(yè)務(wù)邏輯,然后將郵件展示給用戶(hù)瀏覽。所以在這個(gè)圖中將最少有 3 個(gè)模塊,他們會(huì)由不同的團(tuán)隊(duì)來(lái)分別負(fù)責(zé)。當(dāng)整個(gè)系統(tǒng)開(kāi)發(fā)完畢之后,各個(gè)團(tuán)隊(duì)需要將各自的組件發(fā)布到運(yùn)行環(huán)境當(dāng)中。因?yàn)?MailboxAPI 模塊(MailboxAPI.jar)是被所有的其他組件所依賴(lài)的,為了將來(lái)維護(hù)和發(fā)布的方便,一般 MailboxAPI.jar 會(huì)被放置到 WAS 的 lib 目錄下,這樣,其他的每一個(gè)組件都能輕松的找到它,而 MailboxAPI 模塊團(tuán)隊(duì)也可以輕松地發(fā)布和維護(hù) MailboxAPI,因?yàn)榘l(fā)布位置的唯一,MailboxAPI 模塊的每一次發(fā)布和維護(hù)將不需要通知到所有其他的團(tuán)隊(duì)。而其他的模塊,因?yàn)榘瑯I(yè)務(wù)邏輯和展示層,他們一般都是一個(gè) ear 文件,所以他們的發(fā)布位置明顯是與 MailboxAPI.jar 不同的。圖 5 和圖 6 展示給我們 FixedMailbox 和 XMLMailbox 正常運(yùn)行后的樣子。

圖 5. FixedMailbox 的運(yùn)行情況

圖 6. XMLMailbox 的運(yùn)行情況

#T#為了方便大家的學(xué)習(xí),我將已經(jīng)開(kāi)發(fā)好的這 3 個(gè)模塊以附件的形式附在本文上,它們?cè)趬嚎s文件 Version1.zip 里。你只需要解壓縮它,然后將 MailboxAPI.jar 放置在 WAS 的 lib 目錄下,然后啟動(dòng)你的 WAS 系統(tǒng),接著你需要安裝 FixedMailboxReaderEAR.ear 和 XMLMailboxReaderEAR.ear(他們分別代表 FixedMailbox 模塊和 XMLMailbox 模塊)。在 Version1.zip 你還會(huì)發(fā)現(xiàn) FixedMailbox.jar 和 XMLMailbox.jar,它們分別是模塊 FixedMailbox 和 XMLMailbox 的業(yè)務(wù)邏輯,而 FixedMailboxReaderEAR.ear 和 XMLMailboxReaderEAR.ear 是這兩個(gè)模塊的最后封裝。

注意:附件里的每一個(gè)文件里,都含有源碼,以方便感興趣的讀者深入研究。

在整個(gè)郵件系統(tǒng)運(yùn)行一段時(shí)間后,某些用戶(hù)較多的個(gè)別郵件模塊就可能面臨著升級(jí)。因?yàn)榭蛻?hù)多,需求就多,而用戶(hù)的需求又是千奇百怪的,必然會(huì)出現(xiàn)某個(gè)特定的需求波及到了基礎(chǔ)模塊 MailboxAPI。這個(gè)時(shí)候,就可能會(huì)出現(xiàn)如下的情況:模塊 MailboxAPI 和 XMLMailbox 被要求升級(jí),而模塊 FixedMailbox 為了穩(wěn)定,要求不產(chǎn)生任何變化。然而當(dāng) XMLMailbox 的需求很大時(shí),可能使 MailboxAPI 也產(chǎn)生了很大的變化,從而影響了 FixedMailbox,使之不能正常工作,于是版本沖突問(wèn)題產(chǎn)生了。

為了演示這個(gè)問(wèn)題,我改變了模塊 MailboxAPI 和 XMLMailbox 的代碼,產(chǎn)生了版本 2.0 的 MailboxAPI 和 XMLMailbox 模塊,他們被放置在附件 2(Version2.zip)中。為了看到真實(shí)的版本沖突問(wèn)題,請(qǐng)解壓縮 Version2.zip,然后停止 WAS 并刪除 WAS 的 lib 目錄下的 MailboxAPI.jar,接著將 MailboxAPI2.jar 放置在 WAS 的 lib 目錄下,然后重啟你的 WAS 系統(tǒng),接著你需要用 XMLMailboxReaderEAR2.ear 去升級(jí)已經(jīng)存在的 XMLMailboxReader 應(yīng)用,然后分別訪問(wèn)兩個(gè)模塊的 Servlet,你就會(huì)看到 FixedMailbox 模塊將不能正常工作,而 XMLMailbox 則一切正常,如圖 7 或圖 8 所示。

圖 7. FixedMailbox 不能正常運(yùn)行

圖 8. XMLMailbox 可以運(yùn)行

注意:如果你不刪除 MailboxAPI.jar,而是讓 MailboxAPI.jar 和 MailboxAPI2.jar 并存在 WAS 的 lib 目錄下,那么就有可能是 FixedMailbox 能正常工作,而 XMLMailbox 不能正常工作,如圖 9 和圖 10 所示,原因是 MailboxAPI.jar 可能在 MailboxAPI2.jar 之前被載入到類(lèi)加載器中了??傊現(xiàn)ixedMailbox 和 XMLMailbox 將不能同時(shí)工作,這就是版本沖突問(wèn)題。

圖 9. 當(dāng) MailboxAPI.jar 和 MailboxAPI2.jar 并存時(shí),F(xiàn)ixedMailbox 可以正常運(yùn)行

圖 10. 當(dāng) MailboxAPI.jar 和 MailboxAPI2.jar 并存時(shí),XMLMailbox 不能運(yùn)行

講述如何將這個(gè)樣例程序中的某些組件轉(zhuǎn)變成 WAS 上的 OSGi bundle,從而解決了版本沖突問(wèn)題

為了解決在第五章中的版本沖突問(wèn)題,我們只需要將模塊 FixedMailbox 和 XMLMailbox 的業(yè)務(wù)邏輯部分(FixedMailbox.jar 和 XMLMailbox.jar)轉(zhuǎn)變成 OSGi 的 bundle,然后將 MailboxAPI 的版本 1 和版本 2(MailboxAPI.jar 和 MailboxAPI2.jar)也都轉(zhuǎn)變成 bundle,并使 FixedMailbox.jar 依賴(lài)于 MailboxAPI.jar,使 XMLMailbox.jar 依賴(lài)于 MailboxAPI2.jar。接下來(lái),將 WAS 的 lib 目錄下的 MailboxAPI 模塊移除掉,然后將 FixedMailbox.jar、XMLMailbox.jar、MailboxAPI.jar 和 MailboxAPI2.jar 同時(shí)放入 WAS 的 plugins 目錄下,最后重新啟動(dòng) WAS,你會(huì)發(fā)現(xiàn)模塊 FixedMailbox 和 XMLMailbox 能同時(shí)工作,如圖 11 和圖 12 所示。

圖 11. 在將 FixedMailbox.jar 轉(zhuǎn)變?yōu)?bundle 后,F(xiàn)ixedMailbox 可以正常運(yùn)行

圖 12. 在將 XMLMailbox.jar 轉(zhuǎn)變?yōu)?bundle 后,XMLMailbox 可以正常運(yùn)行

在將整個(gè)郵件系統(tǒng)轉(zhuǎn)變成支持 OSGi bundle 后,會(huì)使郵件系統(tǒng)的各個(gè)模塊之間的依賴(lài)關(guān)系從圖 4 編程圖 13 的情況,因?yàn)樵?OSGi 中,同一模塊的多個(gè)版本可以并存,并且模塊之間的依賴(lài)關(guān)系可以通過(guò)版本進(jìn)行限制,從而是 Java 應(yīng)用軟件中的版本沖突問(wèn)題得到了完美的解決。

圖 13. 最后的郵件系統(tǒng)的模塊之間的依賴(lài)關(guān)系

將已有的 Jar 文件轉(zhuǎn)換成 bundle 非常簡(jiǎn)單,我們不需要改變?nèi)魏?Java 代碼,只需要將必要的 OSGi 的 bundle 信息加入 Jar 文件的 MANIFEST.MF。為了方便大家的查看,我將已經(jīng)轉(zhuǎn)好的 bundle 文件 FixedMailbox.jar、XMLMailbox.jar、MailboxAPI.jar 和 MailboxAPI2.jar 做成了附件 3。

總結(jié)

OSGi 框架是實(shí)現(xiàn) Java 應(yīng)用軟件模塊化的重要手段。當(dāng)前,OSGi 已經(jīng)變的非常流行,很多的著名的 Java 應(yīng)用在底層已經(jīng)開(kāi)始采用 OSGi 框架,比如說(shuō) Spring,IBM 的 Eclipse 和 WebSphere Application Server。所以將你自己的 Java 應(yīng)用轉(zhuǎn)變成支持 OSGi 是必要的趨勢(shì),而本文將給你一個(gè)范例,告訴你如何在 WebSphere Application Server 中將你的應(yīng)用轉(zhuǎn)變成支持 OSGi,從而就可以避免版本沖突問(wèn)題的發(fā)生。


本文標(biāo)題:OSGi全面總結(jié)與WebSphere應(yīng)用范例
分享URL:http://www.dlmjj.cn/article/dhcejgg.html