複製鏈接
請複製以下鏈接發送給好友

OSGI

(面向Java的動態模型系統)

鎖定
OSGi(開放服務網關協議,Open Service Gateway Initiative)技術是Java動態化模塊化系統的一系列規範。OSGi一方面指維護OSGi規範的OSGI官方聯盟,另一方面指的是該組織維護的基於Java語言的服務(業務)規範。簡單來説,OSGi可以認為是Java平台的模塊層。OSGi服務平台向Java提供服務,這些服務使Java成為軟件集成和軟件開發的首選環境。OSGi技術提供允許應用程序使用精煉、可重用和可協作的組件構建的標準化原語,這些組件能夠組裝進一個應用和部署中。
中文名
開放服務網關協議
外文名
Open Service Gateway Initiative
學    科
軟件工程
應用對象
Java動態模型系統
類    別
網關協議
特    點
穩定、高效

OSGI簡介

開放服務網關協議有雙重含義。一方面它指OSGi Alliance組織;另一方面指該組織制定的一個基於Java語言的服務規範——OSGi服務平台。 OSGi Alliance是一個由Sun Microsystems、IBM、愛立信等於1999年3月成立的開放的標準化組織,最初名為Connected Alliance。該組織及其標準原本主要目的在於使服務提供商通過住宅網關,為各種家庭智能設備提供各種服務。該平台逐漸成為一個為室內、交通工具、移動電話和其他環境下的所有類型的網絡設備的應用程序和服務進行傳遞和遠程管理的開放式服務平台。
該規範和核心部分是一個框架,其中定義了應用程序的生命週期模式和服務註冊。基於這個框架定義了大量的OSGi服務:日誌、配置管理、偏好,HTTP(運行servlet)、XML分析、設備訪問、軟件包管理、許可管理、星級、用户管理、IO連接、連線管理、Jini和UPnP。
這個框架實現了一個優雅、完整和動態的組件模型。應用程序(稱為bundle)無需重新引導可以被遠程安裝、啓動、升級和卸載(其中Java包/類的管理被詳細定義)。API中還定義了運行遠程下載管理政策的生命週期管理。服務註冊允許bundles去檢測新服務和取消的服務,然後相應配合。OSGI框架一般具備的基礎功能:
支持模塊化的動態部署。基於OSGI而構建的系統可以以模塊化的方式動態地部署至框架中,從而增加、擴展或改變系統的功能。支持模塊化的封裝和交互。每個工程(模塊)可通過聲明Export-Package對外提供訪問此工程的類和接口。
支持模塊的動態擴展。基於OSGI提供的面向服務的組件模型的設計方法,以及OSGI實現框架提供的擴展點方法可實現模塊的動態擴展。模塊化的設計。在OSGI中模塊由一個或多個bundle構成,模塊之間的交互通過Import-Package、Export-Package以及OSGI Service的方式實現。
動態化的設計。動態化的設計是指系統中所有的模塊必須支持動態的插拔和修改,“即插即用,即刪即無”。
可擴展的設計。通常使用定義擴展點的方式。按照Eclipse推薦的擴展點插件的標準格式定義bundle中的擴展點,其它要擴展的bundle可通過實現相應的擴展點來擴展該bundle的功能。每個bundle擁有獨立的class loader,通過它來完成本bundle類的加載。
穩定、高效的系統。基於OSGI的系統採用的是微核機制,微核機制保證了系統的穩定性,微核機制的系統只要微核是穩定運行的,那麼系統就不會崩潰,也就是説基於OSGI的系統不會受到運行在其中的bundle的影響,不會因為bundle的崩潰而導致整個系統的崩潰。 [1] 
OSGI OSGI
OSGi服務平台提供在多種網絡設備上無需重啓的動態改變構造的功能。為了最小化耦合度和促使這些耦合度可管理,OSGi技術提供一種面向服務的架構,它能使這些組件動態地發現對方。OSGi聯盟已經開發了例如像HTTP服務器、配置、日誌、安全、用户管理、XML等很多公共功能標準組件接口。這些組件的兼容性插件實現可以從進行了不同優化和使用代價的不同計算機服務提供商得到。然而,服務接口能夠基於專有權基礎上開發。
因為OSGi技術為集成提供了預建立和預測試的組件子系統,所以OSGi技術使你從改善產品上市時間和降低開發成本上獲益。因為這些組件能夠動態發佈到設備上,所以OSGi技術也能降低維護成本和擁有新的配件市場機會。

OSGI安全協議

安全機制是建立在Java和Java2安全模型基礎之上。Java語言的設計對很多結構進行了限制。例如病毒中經常遇到的緩存溢出是不可能發生的。Java語言中的訪問控制符限制了代碼可見性。
OSGI平台通過使用私有類(在Java中不能用標準方式使用的機制)擴展了該模型。Java2安全模型提供了一個完整模塊檢查代碼對於資源的可訪問性。OSGI增加了完全動態的權限管理,簡化了操作者和系統管理員的工作。
OSGI聯盟已經定義了很多協議服務,這些服務將外部協議映射為OSGI服務。HTTP服務(HttpService)該HTTP服務是servlet運行器。bundles提供servlets,這些服務端小程序基於HTTP協議成為可用的。OSGi服務平台的動態更新功能使HTTP服務成為一個非常具有吸引力的Web服務器,它能伴隨着新的servlet被更新,如果需要可以遠程更新而無需重啓。
UPnP服務(UPnPService)通用即插即用(UPnP)是一個正在形成中的消費電子標準。OSGi中的UPnP服務在一個UPnP網絡上將設備映射到服務註冊中。同樣,它也可以將OSGi服務映射到UPnP網絡。這是發佈版本3中的推薦規範。
DMT管理(DMTAdmin)開放移動聯盟(OMA)基於設備管理樹為移動設備管理提供了一個完整規定。DMT管理服務定義該樹如何被訪問和/或者在OSGi服務平台中被擴充。

OSGI框架結構

OSGI規範的核心組件是OSGI框架。這個框架為應用程序(被叫做組件(bundle))提供了一個標準環境。整個框架可以劃分為一些層次:
OSGI OSGI
L0:運行環境
L1:模塊
L2:生命週期管理
L3:服務註冊
還有一個無處不在的安全系統滲透到所有層。
L0層執行環境是Java環境的規範。Java2配置和子規範,像J2SE,CDC,CLDC,MIDP等等,都是有效的執行環境。OSGi平台已經標準化了一個執行環境,它是基於基礎輪廓和在一個執行環境上確定了最小需求的一個小一些的變種,該執行環境對OSGi組件是有用的。
L1模塊層定義類的裝載策略。OSGi框架是一個強大的具有嚴格定義的類裝載模型。它基於Java之上,但是增加了模塊化。在Java中,正常情況下有一個包含所有類和資源的類路徑。OSGi模塊層為一個模塊增加了私有類同時有可控模塊間鏈接。模塊層同安全架構完全集成,可以選擇部署到部署封閉系統,防禦系統,或者由廠商決定的完全由用户管理的系統。
L2生命週期層增加了能夠被動態安裝、開啓、關閉、更新和卸載的bundles。這些bundles依賴於於具有類裝載功能的模塊層,但是增加了在運行時管理這些模塊的API。生命週期層引入了正常情況下不屬於一個應用程序的動態性。擴展依賴機制用於確保環境的操作正確。生命週期操作在安全架構保護之下,使其不受到病毒的攻擊。
L3層增加了服務註冊。服務註冊提供了一個面向bundles的考慮到動態性的協作模型。bundles能通過傳統的類共享進行協作,但是類共享同動態安裝和卸載代碼不兼容。服務註冊提供了一個在bundles間分享對象的完整模型。定義了大量的事件來處理服務的註冊和刪除。這些服務僅僅是能代表任何事物的Java對象。很多服務類似服務器對象,例如HTTP服務器,而另一些服務表示的是一個真實世界的對象,例如附近的一個藍牙手機。這個服務模塊提供了完整安全保障。該服務安全模塊使用了一個很聰明的方式來保障bundles之間通信安全。

OSGI標準服務

OSGI OSGI
在該框架之上,OSGi聯盟定義了很多服務。這些服務通過一個Java接口指定。bundles能夠實現這個接口,並在註冊服務層註冊該服務。服務的客户端在註冊庫中找到它,或者當它出現或者消失時做出響應。這個同SOA架構使用Web服務進行發佈的方式相似。
兩者主要不同是Web服務總是需要傳輸層,這個使它比採用直接方法調用的OSGi服務慢幾千倍。同時,OSGi組件能夠對這些服務的出現和消失做出響應。更多的信息可以從OSGi服務平台發行版本4手冊或者PDF下載中找到。需要注意的是每一種服務都是抽象定義的,與不同計算機服務商的實現相獨立。

OSGI框架服務

OSGI OSGI
OSGi框架提供一個權限管理服務,一個包管理服務和一個開始級別服務。這些服務是一個可選部分,指示框架的操作。框架服務如下:
權限管理(PermissionAdmin)的bundles的權限通過這種服務進行維護。一旦設置了它們,權限服務立即激活。
包管理(PackageAdmin),bundles同類和資源分享包。bundles的更新可能需要系統重新計算這些依賴。這個包管理服務提供關於系統的實際包分享狀態和能夠刷新已經共享的包。也就是,取消依賴和重新計算依賴。
啓動級別(StartLevel)。啓動級別是一個bundles集合,它們應該同時運行或者應該在其它已經啓動以前被初始化。啓動級別服務設置當前的啓動級別,為每個bundle排一個啓動級別和審核當前的設置。
URL處理者(URLHandler)。Java環境為URL處理者支持一個提供者模型。然而,這是一個單件,不可能在一個象OSGi可能有很多提供者的協作環境上使用它。此服務規範使任何組件提供額外的URL處理者。

OSGI系統服務

OSGI OSGI
系統服務提供水平功能,它在每個系統是必須的。日誌服務,配置管理服務,設備訪問服務,用户管理服務,IO連接器服務和參數服務都是系統服務的一個方面。
日誌服務(LogService),日誌信息,警告,調試或者錯誤信息通過日誌服務來處理的。它接受日誌實體並分派這些實體到訂閲了這個信息的其他bundles。
配置管理服務(ConfigurationAdminService),該服務提供一個設置和獲取配置信息的靈活、動態模型。
設備訪問服務(DeviceAccessService),設備訪問是OSGi為一個新的設備匹配一個驅動,並自動下載一個實現該驅動的bundles的機制。這個可用作即插即用方案。
用户管理服務(UserAdminService),該服務使用一個用於授權和驗證目的的用户信息數據庫。
IO連接器服務(IOConnectorService),該IO連接器服務實現了CDC/CLDCjavax包,並作為一個服務。該服務允許bundles提供新的可交換協議模式。
參數服務(PreferencesService),該服務提供了參數層級數據庫的可訪問性,同Windows註冊表或者Java參數類相似。
組件運行時服務(ComponentRuntime),服務的動態特性--它們能夠在任何時間來去自由--使編寫軟件變得更難。組建運行時規範通過提供一個基於依賴聲明的XML文件來簡化處理這些動態方面。
部署管理服務(DeploymentAdmin),OSGi的主要部署格式是bundle,它是一個JAR/ZIP文件。部署管理提供第二種可選格式:部署包。部署包能夠將bundles和相應資源聯接成可被安裝和卸載的單個交付。完整的資源處理器模型允許用户代碼擴充資源類型。
事件管理服務(EventAdmin),很多OSGi事件有特定的類型化的接口,使其很難接收和過濾事件。事件服務提供一個泛化的基於主題的事件機制。這個規範包括為所有已存框架和服務事件的映射。
應用程序管理服務(ApplicationAdmin),OSGibundle模型不同於依賴於啓動和關閉形式的典型的桌面或者移動電話應用程序模型。該應用程序管理服務提供了傳統應用程序模型和它所要求的管理設施。

OSGIHelloWorld

0.前言
這篇文檔介紹如何使用OSGi框架的一個實現——Equinox來教你如何配置一個簡單的OSGi開發環境,並且在這個環境上開發一個HelloWorld程序,這其中會涵蓋前面的入門篇講到的三個層次的內容,讓你在實踐的同時鞏固之前瞭解的內容。話不多説,我們開始吧!
開發環境建立
1.1 Equinox是什麼
從代碼角度來看,Equinox其實就是OSGi核心標準的完整實現,並且還在這個基礎上增加了一些額外的功能(比如為框架增加了命令行和程序執行的入口)。我們在之前入門篇講解的東西其實都是OSGi核心標準的一小部分。其實它的核心就是一個jar包,這個jar包既能執行(作為標準Java包的特性),也是一個bundle(Manifest裏面含有OSGi bundle特有的元數據)。
能夠利用Equinox項目的代碼來運行一個實實在在的OSGi框架,框架啓動後,你就可以將你開發好bundle放到裏面運行。
1.2下載Equinox
Equinox在Eclipse官方網站上有下載,裏面列出了各個版本供我們選擇:
在這裏,我們使用3.7版本的Equinox,下載好以後放在一個單獨的文件夾下(這裏我的路徑是E:\OSGi framework\equinox)
1.3 從命令行啓動框架
如果啓動這個框架的話,有了上面的jar包就足夠了,我們進入命令行輸入如下命令:java –jar org.eclipse.osgi_3.7.0.v20110613.jar -console ,然後就會進入Equinox的控制枱:
如果出現osgi>的提示符,就説明啓動成功了。
Equinox的控制枱的部分基本命令如下(區分大小寫):
install [URL]
將URL表示的bundle安裝到框架中
uninstall [bundleID]
將id=bundleID的bundle卸載
start [bundleID]
啓動一個bundle
stop [bundleID]
停止一個bundle
refresh [bundleID]
刷新bundle
update [bundleID]
更新bundle 的內容
ss
簡單顯示所有bundle的狀態
status
展示安裝的bundle和註冊的服務
headers [bundleID]
展示bundle 的manifest中的元數據
1.4 Eclipse建立環境
在上一節中大家看到啓動和控制框架的方法,是相當簡單的一個過程。不過單單只是運行環境還不夠,我們還需要開發環境。
1.4.1 設置
首先我們不需要安裝必須的插件,只要你有較新版本的Eclipse就行了。然後進入Eclipse的window->preferences界面,選中Plug-in Development下的Target Platform
右邊只有一個Runing Platform的,我們任務是點擊“Add…”按鈕來增加一個我們自己的的platform,進入如下界面:
選擇默認的第一個就好,點擊next。
再點擊這裏的“Add…”:
選擇“Directory”:
選擇你的Equinox的jar包所在的路徑,然後點擊finish,回到剛才的界面:
這時候你就會發現裏面多出來了你剛剛設置的路徑,路徑後面描述的“1 plug-ins available”則就是説的我們放置的Equinox的jar包。
繼續點擊finish,回到最開始的界面
這時候多出來了一個新的target platform,勾選上,然後確定。
1.4.2 啓動
打開菜單項Run->Run configurations…,在OSGi Framework項中,新建一個Runconfiguration:
已經自動包含了Equinox的jar包了,點擊Run,看看運行的效果:
圖1 圖1
Eclipse的控制枱中也出現來了osgi的提示符,説明你已經成功啓動了。
你可以試試剛才講的那些命令,看看能輸出些什麼(比如圖1中我輸入了ss)。
1.4.3 新建一個project
打開新建project的界面,選擇Plug-in Project:
然後輸入project的名字,TargetPlatform處選擇an OSGi framework->Equinox或者standard都行,點擊下一步:
這裏實際上是對bundle的Manifest文件的設置,其中的ID就是Bundle-SymbolicName,Version就是bundle的版本號,下面還能決定是否定義BundleActivator,點擊finish就創建了一個project
至此,開發環境已經建立完畢(這個project只是為了演示怎麼建立,不會在接下來的內容中用到,可刪之)。
2 HelloWorld代碼
可謂是萬事具備,只欠Helloworld了。為了將OSGi框架的三個層次都涵蓋到,這個Helloworld可能會比其他你見到的OSGi Helloworld程序要複雜一點點。如果對代碼中的一些API感到生疏,記得回到之前的入門篇中找到對應的內容,這樣對你理解代碼會有幫助。裏面的關鍵代碼已經用黃色高亮顯示。(出於篇幅考慮,代碼中的import語句都省略)
2.1 HelloWorld的定義與實現
首先我們創建一個工程org.serc.helloworld,在這個工程裏面,我們創建一個包含sayHello方法的接口,準備作為服務接口:
package org.serc.helloworld;
public interface Hello {
    void sayHello();
}
然後,對這個接口進行實現:
package org.serc.helloworld.impl;
public class HelloImpl implements Hello{
    final String helloString;
    public HelloImpl(String helloString){
        this.helloString= helloString;
    }
    public void sayHello(){
        System.out.println(this.helloString);
    }
}
這個類實現的sayHello所做的工作就是輸出一個在對象構造的時候得到的helloString 字符串。
為了將這個接口暴露出來,我們需要在MANIFEST文件中加入如下條目:
Export-Package: org.serc.helloworld;version="1.0"
接下來,為了把這個服務註冊到框架中,我們定義了一個Activator:
package org.serc.helloworld.activator;
public class Activator implements BundleActivator {
    private List<ServiceRegistration> registrations = new ArrayList<ServiceRegistration>();
    public void start(BundleContext ctx) {
        registrations.add(ctx.registerService(Hello.class.getName(),new HelloImpl("Hello, OSGi"), null));
    }
    public void stop(BundleContext ctx) {
        for(ServiceRegistration registration : registrations) {
        System.out.println("unregistering:"+ registration);
        registration.unregister();
    }
}
我們為這個HelloImpl傳入了"Hello, OSGi"的字符串
為了讓這個Activator能夠工作,需要在MANIFEST文件中做如下定義:
Bundle-Activator:org.serc.helloworld.activator.Activator
這個bundle 最終的MANIFEST內容如下:
Bundle-ManifestVersion:2
Bundle-SymbolicName:org.serc.helloworld
Bundle-Version:1.0
Bundle-Activator:org.serc.helloworld.activator.Activator
Import-Package:org.osgi.framework
Export-Package: org.serc.helloworld;version="1.0"
2.2 獲得並執行SayHello服務
創建一個工程org.serc.helloworld.client,創建一個叫HelloUser的BundleActivator,其中的start方法會獲得接口為Hello的服務對象,並且通過這個對象來調用sayHello方法:
package org.serc.helloworld.client;
public class HelloUser implements BundleActivator {
    public void start(BundleContext ctx) {
        ServiceReference ref = ctx.getServiceReference(Hello.class.getName());
        if(ref != null) {
            Hello hello = null;
            try{
                hello= (Hello) ctx.getService(ref);
                if(hello != null)
                    hello.sayHello();
                else
                    System.out.println("Service:Hello---objectnull");
            }catch (RuntimeException e) {
                e.printStackTrace();
            }finally {
                ctx.ungetService(ref);
                hello= null;
            }
        }else {
            System.out.println("Service:Hello---notexists");
        }
    }
    public void stop(BundleContext ctx) throws Exception {
    }
}

為了獲得Hello這個接口的定義,我們還需要在MANIFEST文件中import Hello所在的package:
Bundle-ManifestVersion:2
Bundle-SymbolicName:org.serc.helloworld.client
Bundle-Version:1.0
Bundle-Activator:org.serc.helloworld.client.HelloUser
Import-Package:org.serc.helloworld;version="[1.0,2.0)",org.osgi.framework

2.3 HelloWorld程序的流程
可能光看代碼會比較不容易看清楚程序的執行流程,圖2表示了這幾個類的各個功能的相互依賴關係,整個關係從Hello接口的定義開始;然後到Hello接口被實現,得到HelloImpl;再到Activator將HelloImpl註冊為框架中的一個服務,再到HelloUser通過與框架交互得到剛才註冊的服務,並且使用這個服務從而輸出字符串;最後一個可選流程是當我們stop org.serc.helloworld這個bundle的時候,程序會將之前註冊的服務註銷掉。
圖2 圖2
2.4 程序的執行
通過上面的工作,我們得到了兩個自己定義的bundle:
org.serc.helloworld
org.serc.helloworld.client
打開Run configurations界面,我們會看見Bundles標籤裏面多出來了這兩個bundle:
也就是説,OSGi框架在啓動的時候,會自動install和start這2個bundle。
2.5 利用命令行查看程序執行過程中框架狀態的變化
2.4其實只給出了一個結果,如果你還不太清楚這個結果具體是怎麼出來的,那麼這一節的內容應該能夠幫助你更好的理解輸出結果的過程。下面我們通過Equinox的一些命令行來一步一步安裝和執行bundle,並且查看過程中框架的狀態變化,來讓你們搞清楚這個結果是怎麼來的。
首先在Run configuration中取消兩個helloworld bundle的自動啓動:
然後點擊Run,這時候就不會立即輸出Hello, OSGi字符串了,先用“ss”命令查看bundle 的狀態:
可見兩個bundle並不是出於ACTIVE狀態,説明並沒有啓動,我們執行“start 8”來啓動org.serc.helloworld這個bundle
在用services命令查看當前已經註冊的服務,我們會看到一大堆的系統服務中多出來如下一項服務
這顯然是我們在start以後註冊上去的,但是還沒有任何一個bundle在使用這個服務。
接下來我們start 9號bundle,也就是我們用來調用服務的bundle
這時就輸出了“Hello, OSGi”的字符串。
那麼如果我們先啓動9號bundle而不啓動8號bundle會怎麼樣呢?大家可以試一試,因為我們在代碼中已經對沒有服務的異常情況做了處理,屆時會有相應的輸出。
我們先停止8號bundle
大家可以看見剛才註冊的服務已經被註銷了,我們執行refresh 11(也就是剛才的9號bundle)來重新執行其中BundleActivator的start方法
可見Hello服務已經不復存在了。從這裏我們可以看出來,其實Bundle的啓動順序也是一個需要注意的環節,有時候你所定義的bundle是具有順序敏感性的,必須要某些前置bundle啓動了以後,後面的bundle才能正確啓動。
3 小結
這篇文檔是入門篇的最後一章了,希望讀者在花時間看完這4篇文檔並且動手實踐後能夠有所收穫,並且對OSGi框架的工作原理及其優勢能有一個比較清晰的瞭解和認識。

OSGI相關書籍

深入理解OSGi 深入理解OSGi
1.《深入理解OSGi:Equinox原理、應用與最佳實踐》 [2] 
作者:周志明 & 謝小明,出版時間:2013-2-1.
內容簡介:本書共14章,分4個部分。第一部分(第1章):走近OSGi,主要介紹了什麼是OSGi以及為什麼要使用OSGi。第二部分(第2~4章):OSGi規範與原理,對最新的OSGi R5.0中的核心規範進行了全面的解讀,首先講解了OSGi模塊的建立、描述、依賴關係的處理,然後講解了Bundle的啓動原理和調度管理,最後講解了與本地及遠程服務相關的內容。第三部分:OSGi服務與Equinox應用實踐(第5~11章),不僅詳細講解了OSGi服務綱要規範和企業級規範中最常用的幾個子規範和服務的技術細節,還通過一個基於Equinox的BBS案例演示了Equinox的使用方法,最重要的是還通過源碼分析了Equinox關鍵功能的實現機制和原理。第四部分:最佳實踐(第12~14章),總結了大量關於OSGi的最佳實踐,包括從Bundle如何命名、模塊劃分、依賴關係處理到保持OSGi動態性、管理程序啓動順序、使用API基線管理模塊版本等各方面的實踐技巧,此外還介紹了Spring DM的原理以及如何在OSGi環節中進行程序測試。
Eclipse RCP與Spring OSGi Eclipse RCP與Spring OSGi
2.《Eclipse RCP與Spring OSGi:技術詳解與最佳實踐》 [3] 
作者:陸陽,出版時間:2013-1-1.
內容簡介:全書共分3個部分:基礎篇(第1~5章)詳細介紹了與Eclipse RCP相關的一系列核心概念、Eclipse RCP開發環境的搭建,以及SWT、JFace、Forms、Nebula和WindowBuilder等Eclipse RCP開發所常用的界面編程技術;高級篇(第6~12章)系統講解了Eclipse RCP應用開發的基礎知識、Eclipse RCP軟件產品各個組成部分的構建方法,以及Eclipse RCP擴展的使用和擴展點的開發,掌握這些技術知識的讀者將能構建一個結構完整的Eclipse RCP軟件,並解決軟件開發過程中遇到的故障;實戰篇(第13~15章)詳細講解了Eclipse RCP與Spring OSGi框架、Hibernate ORM框架、JPA規範、Maven工具的整合,以及它與Java的模塊化設計。
3.osgi中文社區
簡介:由北京大學軟件工程國家工程研究中心“軟件協同研發支撐技術”組維護的一個模塊化動態化開發技術的公益社區。初學者、進階者和大牛都可以在這裏分享技術和經驗,自由的交流和學習,在貢獻和收穫中充實自己。為更多的學生、研究者和從業者提供更廣闊的交流平台。
參考資料