溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

架構(gòu)設(shè)計(jì)——OSGI規(guī)范

發(fā)布時(shí)間:2020-08-03 03:31:35 來(lái)源:網(wǎng)絡(luò) 閱讀:28181 作者:天山老妖S 欄目:軟件技術(shù)

架構(gòu)設(shè)計(jì)——OSGI簡(jiǎn)介

一、OSGI簡(jiǎn)介

1、OSGI簡(jiǎn)介

OSGI(Open Service Gateway Initiative),即開(kāi)放服務(wù)網(wǎng)關(guān)協(xié)議,是面向Java的動(dòng)態(tài)模型系統(tǒng)。
OSGI是指由OSGI Alliance組織制定的Java模塊化規(guī)范,OSGI規(guī)范的核心部分是一個(gè)框架,其中定義了應(yīng)用程序的生命周期模式和服務(wù)注冊(cè)?;贠SGI框架定義了大量的OSGI服務(wù):日志、配置管理,HTTP服務(wù)(運(yùn)行Servlet)、XML解析、設(shè)備訪問(wèn)、軟件包管理、許可管理、用戶管理、IO連接、Jini和UPnP等。
OSGI中文社區(qū):http://www.osgi.com.cn/?
OSGI官方網(wǎng)站:https://www.osgi.org/
OSGI框架實(shí)現(xiàn)了一個(gè)優(yōu)雅、完整和動(dòng)態(tài)的組件模型,組件(bundle)無(wú)需重新引導(dǎo)可以被遠(yuǎn)程安裝、啟動(dòng)、升級(jí)和卸載。
OSGI服務(wù)平臺(tái)提供在多種網(wǎng)絡(luò)設(shè)備上無(wú)需重啟的動(dòng)態(tài)改變構(gòu)造的功能。
為了最小化耦合度和促使耦合度可管理,OSGI技術(shù)提供了一種面向服務(wù)的架構(gòu),使組件動(dòng)態(tài)地發(fā)現(xiàn)對(duì)方。
OSGI聯(lián)盟已經(jīng)開(kāi)發(fā)了如HTTP服務(wù)器、配置、日志、安全、用戶管理、XML等很多公共功能標(biāo)準(zhǔn)組件接口。標(biāo)準(zhǔn)組件的兼容性插件實(shí)現(xiàn)可以從不同計(jì)算機(jī)服務(wù)提供商得到。
OSGi的主要職責(zé)就是為了讓開(kāi)發(fā)者能夠創(chuàng)建動(dòng)態(tài)化、模塊化的Java系統(tǒng)。

2、OSGI規(guī)范的組成

OSGI規(guī)范包括以下子規(guī)范:
A、Framework規(guī)范(OSGI核心,提供一個(gè)安全的可管理的Java Framework來(lái)部署可擴(kuò)展的Java服務(wù))
B、Package Admin Service規(guī)范(管理不同的Bundle之間的引用關(guān)系。當(dāng)Bundle更新或者卸載時(shí)判斷是否有其它的服務(wù)正在使用當(dāng)前的Bundle)
C、Start Level規(guī)范(定義了啟動(dòng)和停止一個(gè)OSGi Service Platform時(shí),不同的Bundles的啟動(dòng)或者停止的先后順序)
D、Permission Admin Service規(guī)范(Bundle是否許可執(zhí)行另外的Bundle的代碼)
E、URL Handlers Service規(guī)范(怎樣注冊(cè)URL Schema,如何將java.io.InputStream對(duì)象轉(zhuǎn)換為特定的Java對(duì)象)
F、Log Service規(guī)范
G、Configuration Admin Service規(guī)范
H、Device Access Specification
I、User Admin Service Specification
J、IO Connector Service Specification
K、Http Service Specification
L、Preference Service Specification
M、Wire Admin Service Specification
N、XML Parser Service Specification
O、Metatype Specification
P、Service Tracker Specification
Q、Measurment and State Specification
R、Position Specification
S、Execution Environment Specfication

3、OSGI的優(yōu)點(diǎn)

OSGI的優(yōu)勢(shì)主要表現(xiàn)在以下幾個(gè)方面:
A、熱插拔的插件體系結(jié)構(gòu)
基于OSGI的應(yīng)用程序可動(dòng)態(tài)更改運(yùn)行狀態(tài)和行為。在OSGI框架中,每一個(gè)組件都是可熱插拔的,因此,對(duì)某一特定的組件的修改并不會(huì)影響到容器中的所有組件,運(yùn)行中的大部分組件依舊能照常工作,部署一個(gè)新的Bundle時(shí)也不需要重新啟動(dòng)服務(wù)器。
B、可復(fù)用性
OSGI框架本身可復(fù)用性極強(qiáng),易于構(gòu)建真正面向接口的程序架構(gòu),每一個(gè)組件(Bundle)都是一個(gè)獨(dú)立可復(fù)用的單元?;贠SGI獨(dú)特的特性,進(jìn)行企業(yè)開(kāi)發(fā)的時(shí)候,對(duì)于新的開(kāi)發(fā),可以從企業(yè)的組件庫(kù)中精簡(jiǎn)出可復(fù)用的模塊,量身定做新的組件,最大限度的利用了已有的資源,降低開(kāi)發(fā)成本,增強(qiáng)企業(yè)的競(jìng)爭(zhēng)力。
C、高效性,穩(wěn)定性
OSGI是一個(gè)穩(wěn)定而高效的系統(tǒng)。OSGI作為一個(gè)微核的系統(tǒng),其核心只有為數(shù)不多的幾個(gè)JAR包?;贠SGI框架的系統(tǒng)的低耦合性,其結(jié)構(gòu)的優(yōu)勢(shì)性保證具體的某一個(gè)組件不至于影響到全局,更不會(huì)因?yàn)榫植康腻e(cuò)誤導(dǎo)致全局系統(tǒng)的崩潰。

4、OSGI的缺點(diǎn)

A、每個(gè)組件(Bundle)都由單獨(dú)的類加載器加載,與一些Java EE項(xiàng)目中使用比較多的框架整合比較困難,如Spring MVC、Struts2等。
B、目前OSGI框架提供的管理端不夠強(qiáng)大,現(xiàn)在的管理端中僅提供了基本的組件狀態(tài)管理、日志查看等功能,像動(dòng)態(tài)修改系統(tǒng)級(jí)別的配置(config.ini)、動(dòng)態(tài)修改組件的配置(Manifest.mf)、啟動(dòng)級(jí)別等功能都尚未提供。
C、采用OSGI作為規(guī)范的模塊開(kāi)發(fā)、部署方式自然給現(xiàn)有開(kāi)發(fā)人員提出了新的要求,需要學(xué)習(xí)新的基于OSGI的開(kāi)發(fā)方式。

二、OSGI框架原理

1、OSGI框架簡(jiǎn)介

OSGI框架從概念上可以分為三層:模塊層、生命周期層和服務(wù)層。
Module Layer:模塊層主要涉及包及共享的代碼;
Lifecycle Layer:生命周期層主要涉及組件的運(yùn)行時(shí)生命周期管理;
Service Layer:服務(wù)層主要涉及模塊之間的交互和通信。
架構(gòu)設(shè)計(jì)——OSGI規(guī)范
OSGI Framework是OSGI Service Platform規(guī)范的核心組成部分,提供了一個(gè)通用的、安全可管理的Java framework。通過(guò)OSGI Framework可以支持一種叫做組件的Service application的部署和擴(kuò)展。
OSGI兼容設(shè)備可以下載并且安裝OSGI組件,也可一旦不再需要的時(shí)候刪除。組件安裝后會(huì)注冊(cè)一定數(shù)量的Services,并被由同一個(gè)Framework下的其它組件使用。
在一個(gè)動(dòng)態(tài)擴(kuò)展的的OSGI環(huán)境中,F(xiàn)ramework管理組件的安裝和更新,同時(shí)也管理組件和Services之間的依賴關(guān)系。
Framework提供給組件開(kāi)發(fā)者必須的資源來(lái)在Java平臺(tái)上開(kāi)發(fā),為開(kāi)發(fā)的組件提供了代碼動(dòng)態(tài)加載的功能, 也使得開(kāi)發(fā)者開(kāi)發(fā)、部署一個(gè)大規(guī)模的Services變的很容易。
其次,F(xiàn)ramework為Java組件開(kāi)發(fā)者提供了簡(jiǎn)明一致的編程模型,簡(jiǎn)化了開(kāi)發(fā)部署的復(fù)雜性。編程模型允許開(kāi)發(fā)者將自己的接口規(guī)范綁定到OSGI環(huán)境中的Service。
一個(gè)一致的編程模型幫助開(kāi)發(fā)者可以應(yīng)付一些可估計(jì)的危急錯(cuò)誤。Framework將會(huì)運(yùn)行在不同的硬件環(huán)境上,但一致的接口確保組件可以運(yùn)行在一致的服務(wù)接口上。

2、模塊層

模塊層是OSGi框架中最基礎(chǔ)的部分。
OSGi的模塊化,是通過(guò)為Jar包添加metadata 來(lái)定義哪些類該暴露,哪些類該隱藏,其控制單元叫做組件Bundle(jar包)。?
Bundle是以jar包形式存在的一個(gè)模塊化物理單元,包含代碼、資源文件和元數(shù)據(jù)(metadata),并且jar包的物理邊界也是運(yùn)行時(shí)邏輯模塊的封裝邊界。
Bundle是OSGi中的基本組件,其表現(xiàn)形式仍然為Java概念中傳統(tǒng)的Jar包。
通過(guò)META-INF目錄下的MANIFEST.MF文件對(duì)其予以進(jìn)一步的定義。
通常一個(gè)MANIFEST.MF文件的內(nèi)容如下:

  Manifest-Version:?1.0
    Bundle-ManifestVersion:?2
    Bundle-Name:?Util
    Bundle-SymbolicName:?com.ibm.director.la.util
    Bundle-Version:?1.0.0
    Bundle-RequiredExecutionEnvironment:?J2SE-1.5
    Import-Package:?org.osgi.framework;version="1.3.0"
    Export-Package:?com.ibm.director.la.util;uses:="org.osgi.framework"
    Bundle-ClassPath:?lib/junit.jar,

MANIFEST.MF文件存儲(chǔ)的實(shí)際上是Bundle的元數(shù)據(jù)。
元數(shù)據(jù)的內(nèi)容可以精確的定義Bundle的各種特征,同時(shí)能更好的對(duì)Bundle進(jìn)行標(biāo)識(shí)同時(shí)幫助用戶對(duì)Bundle進(jìn)行理解。

3、生命周期層

生命周期層在OSGi框架中屬于模塊層上面的一層,生命周期層的運(yùn)作是建立在模塊層的功能之上的。
生命周期層的主要功能是控制動(dòng)態(tài)安裝、開(kāi)啟、關(guān)閉、更新和卸載組件。
生命周期層能夠從外部管理應(yīng)用或者建立能夠自我管理的應(yīng)用(或者兩者的結(jié)合),并且給了應(yīng)用本身很大的動(dòng)態(tài)性。?
Bundle的使用需要生命周期層的API與OSGi框架的生命周期層進(jìn)行交互。

4、服務(wù)層

OSGi服務(wù)是注冊(cè)到OSGi框架中的一個(gè)Java對(duì)象。注冊(cè)的時(shí)候可以設(shè)置Service的屬性。而在獲取Service的時(shí)候可以根據(jù)屬性進(jìn)行過(guò)濾。
Bundle可以通過(guò)Bundle的上下文去注冊(cè)Service或去查詢Service。

三、模塊層

1、模塊化簡(jiǎn)介

模塊化是將一個(gè)大型系統(tǒng)分解為多個(gè)較小的互相協(xié)作的邏輯單元,通過(guò)強(qiáng)制設(shè)定模塊之間的邏輯邊界來(lái)改善系統(tǒng)的維護(hù)性和封裝性。
架構(gòu)設(shè)計(jì)——OSGI規(guī)范
模塊(module)定義了一個(gè)邏輯邊界,模塊本身精確地控制哪些類是完全被封裝起來(lái)的,而哪些類需要暴露出來(lái)作為外部使用。開(kāi)開(kāi)發(fā)者可以輕松地將實(shí)現(xiàn)屏蔽在模塊的內(nèi)部,將公共API暴露在外部。

2、OSGI模塊化與面向?qū)ο?/h4>

面向?qū)ο缶幊讨胁粫?huì)把所有功能都塞到同一個(gè)類。面向?qū)ο缶幊虖膯?wèn)題域中發(fā)現(xiàn)多個(gè)事物,每個(gè)事物負(fù)責(zé)不同的功能,盡量做到高內(nèi)聚和低耦合。面向?qū)ο蟮哪K化粒度在類級(jí)別上。
OSGi的模塊化是通過(guò)為JAR包添加metadata來(lái)定義哪些類應(yīng)該暴露哪些類又隱藏在包中,其控制可見(jiàn)性的粒度是在組件(JAR包)層面上的。
OSGI模塊化和面向?qū)ο笏枷胨鶐?lái)的能力都是通過(guò)控制可見(jiàn)性和可用性來(lái)保證高內(nèi)聚和低耦合的,但粒度不同,一個(gè)是組件層面上,一個(gè)是對(duì)象層面上。

3、JAVA在模塊化方面的局限

A、底層代碼的可見(jiàn)性控制
Java提供了private、public、protected和package private(無(wú)修飾符)四種訪問(wèn)控制級(jí)別,提供了底層的OO數(shù)據(jù)封裝特性。Packege具有分割代碼的作用,但如果包中的代碼要對(duì)包外可見(jiàn),必須設(shè)置為public(protected,使用繼承)。
org.serc.helloworld.Hello.java:定義了一個(gè)接口

package org.serc.helloworld;  

public interface Hello {  
    void sayHello();  
}

org.serc.helloworld.impl.HelloImpl.java:實(shí)現(xiàn)了Hello接口

package org.serc.helloworld.impl;

import org.serc.helloworld.Hello;

public class HelloImpl implements Hello{
    final String helloString;

public HelloImpl(String helloString){
    this.helloString = helloString;
}

public void sayHello(){
    System.out.println(this.helloString);
}
}

org.serc.helloworld.main.Main.java文件:

package org.serc.helloworld.main;

import org.serc.helloworld.Hello;
import org.serc.helloworld.HelloImpl;

public class Main{
    final String helloString;

public static void main(String[] args){
    Hello hello = new HelloImpl(“Hello,SERC!”);
    hello.sayHello();
}

三個(gè)文件分別在不同的包中。HelloImpl實(shí)現(xiàn)細(xì)節(jié)不應(yīng)該暴露給其它包,但從Main.java的main方法中可以看出,為了創(chuàng)建Hello的實(shí)例,必須引入HelloImpl類,但是HelloImpl作為接口的實(shí)現(xiàn)細(xì)節(jié),不應(yīng)該暴露給使用者,違反了封裝的原則。
如果不想讓HelloImpl暴露出來(lái),需要做額外的工作保證既隱藏了實(shí)現(xiàn)細(xì)節(jié),又能簡(jiǎn)單的創(chuàng)建一個(gè)實(shí)現(xiàn)了Hello接口的實(shí)例。可以通過(guò)多種方法(比如工廠模式)來(lái)實(shí)現(xiàn),但增加了與應(yīng)用本身功能無(wú)關(guān)的多余工作,是Java的局限。
B、classpath的局限
在classpath中加入jar包的時(shí)候,只給出文件路徑,而jar包的版本、一致性、依賴性,無(wú)法在classpath中明確的設(shè)置或是從classpath中看出相應(yīng)屬性。
classpath中的jar包是按序加載的,例如:
classpath=/servlet2.2/servlet.jar;/servlet2.3/servlet.jar, 在實(shí)際應(yīng)用的過(guò)程中,Java使用servlet2.2,而不是servlet2.3。如果在大型系統(tǒng)中團(tuán)隊(duì)分開(kāi)開(kāi)發(fā)時(shí),各用各的servlet包,并且版本號(hào)不一樣,在最后將開(kāi)發(fā)結(jié)果合并的時(shí)候,用的是哪個(gè)版本的servlet包就很難搞清楚。
即使classpath能注意到版本的問(wèn)題,也沒(méi)法精確指出依賴。開(kāi)發(fā)者需要根據(jù)提示信息增加依賴包,直到虛擬機(jī)不運(yùn)行到缺包異常為止。
C、OSGI對(duì)JAVA局限的改善
OSGi中很好解決了JAVA的局限性:
包的可見(jiàn)性:OSGi通過(guò)引入包的可見(jiàn)性機(jī)制,能夠完全控制一個(gè)包中的代碼對(duì)哪些模塊可見(jiàn),而不僅僅局限于無(wú)差別的可見(jiàn)性,從而完善了Java的代碼訪問(wèn)控制機(jī)制。
包的版本:OSGi通過(guò)為包增加版本信息,可以精確控制代碼的依賴,保證代碼的版本一致性,彌補(bǔ)了classpath的缺點(diǎn)。

4、組件Bundle簡(jiǎn)介

組件(bundle)是以jar包形式存在的一個(gè)模塊化物理單元,包含了代碼、資源文件和元數(shù)據(jù)(metadata),并且jar包的物理邊界也是運(yùn)行時(shí)邏輯模塊的封裝邊界。
架構(gòu)設(shè)計(jì)——OSGI規(guī)范
在標(biāo)準(zhǔn)的jar包的manifest文件中添加一些組件(bundle)的模塊化特征(metadata)后,jar包就變成了一個(gè)bundle。
bundle和普通jar包最大的區(qū)別就在于元數(shù)據(jù)。
Bundle元數(shù)據(jù)的目的在于準(zhǔn)確描述模塊化相關(guān)的bundle特征,讓OSGi框架對(duì)bundle進(jìn)行各種處理工作(比如依賴解析,強(qiáng)制封裝等),元數(shù)據(jù)主要有三部分:
A、可讀信息(可選)
OSGi標(biāo)準(zhǔn)定義了幾個(gè)元數(shù)據(jù)條目幫助更好地理解和使用bundle,但所有的條目都不是必須的,并且不對(duì)模塊化特性產(chǎn)生任何的影響,OSGi框架會(huì)完全無(wú)視可讀信息。

Bundle-Name: SERC Helloworld
Bundle-Vendor: GR, SERC
Bundle-DocURL: http://elevenframework.org
Bundle-Category: example
Bundle-Copyright: SERC  

B、bundle標(biāo)識(shí)符(必須)
bundle標(biāo)識(shí)符用于唯一的標(biāo)識(shí)一個(gè)bundle。
早期的OSGi標(biāo)準(zhǔn)中并沒(méi)有提供標(biāo)識(shí)一個(gè)已知bundle的方法,直到OSGi R4標(biāo)準(zhǔn),“唯一bundle標(biāo)識(shí)符”被提出來(lái)。為了向后兼容,Bundle-Name不能用來(lái)作為標(biāo)識(shí)符,否則就會(huì)增加維護(hù)向后兼容的工作,所以使用新的manifest屬性Bundle-SymbolicName。
Bundle-SymbolicName: org.serc.helloworld
Bundle-Name是給用戶讀的,而B(niǎo)undle-SymbolicName是給OSGi框架讀的,讓OSGi框架能夠唯一標(biāo)識(shí)一個(gè)bundle。
只用一個(gè)Bundle-SymbolicName肯定是可以唯一標(biāo)識(shí)一個(gè)bundle,但是隨著時(shí)間的推移,bundle可能會(huì)有新版本,加入版本屬性會(huì)讓bundle的信息更加準(zhǔn)確。

Bundle-Name: SERC Helloworld
Bundle-Vendor: GR, SERC
Bundle-DocURL: http://elevenframework.org
Bundle-Category: example
Bundle-Copyright: SERC  

C、代碼可見(jiàn)性(必須)
代碼可見(jiàn)性用于定義內(nèi)部與外部代碼。在JavaSE中的jar包如果放在classpath里,那么jar包對(duì)classpath下的所有程序都是可見(jiàn)的,并且可見(jiàn)性不能改變。而OSGi標(biāo)準(zhǔn)定義了如下的屬性用于描述代碼的可見(jiàn)性:
Bundle-ClassPath:定義了形成bundle的所有代碼所在的位置,Java 中的classpath是定義的jar包的位置,而B(niǎo)undle-ClassPath屬性描述的是bundle內(nèi)部類在bundle中的路徑。例如:
Bundle-ClassPath:.,other-classes/,embedded.jar
Export-Package:顯式暴露需要和其它bundle共享的代碼,每個(gè)包之間用逗號(hào)分隔,每個(gè)包可用修飾詞來(lái)修飾包的其它特征。

Export-Package: org.serc.hellworld; vendor=”SERC”,
org.serc.hellworld.impl; vendor=”Gou Rui” 

Import-Package:定義bundle所依賴的外部代碼,其格式和Export-Package相同,并且也可以使用修飾詞來(lái)修飾包。修飾詞是用來(lái)限制所依賴包的范圍的,類似過(guò)濾器,而不像Export-Package中用來(lái)聲明包的特征。例如:
Import-Package: org.serc.helloworld; vendor=”SERC”

四、生命周期層

1、生命周期層簡(jiǎn)介

生命周期層在OSGi框架中屬于模塊層上面的一層,其運(yùn)作建立在模塊層的功能之上的。生命周期層主要功能是讓開(kāi)發(fā)者能夠從外部管理應(yīng)用或者建立能夠自我管理的應(yīng)用(或者兩者的結(jié)合),并且給應(yīng)用本身很大的動(dòng)態(tài)性。

2、生命周期管理簡(jiǎn)介

一般來(lái)說(shuō),程序(或者程序的一部分)都一定服從某種生命周期。軟件的生命周期有4個(gè)典型的階段,如下:
架構(gòu)設(shè)計(jì)——OSGI規(guī)范
如果正在創(chuàng)建一個(gè)應(yīng)用,首先得安裝(install)應(yīng)用;當(dāng)應(yīng)用的所有依賴都滿足,可以執(zhí)行應(yīng)用;如果應(yīng)用不再需要,可以停止(stop);一段時(shí)間后,可能需要更新(update)應(yīng)用的版本;最終,可能會(huì)移除(remove)應(yīng)用。
通過(guò)在外部或者內(nèi)部對(duì)應(yīng)用進(jìn)行操作,完成對(duì)應(yīng)用的生命周期管理過(guò)程。對(duì)于非模塊化應(yīng)用,操作是以整個(gè)應(yīng)用為對(duì)象的;對(duì)于模塊化應(yīng)用,可以有更細(xì)粒度(針對(duì)應(yīng)用中的某個(gè)模塊)的生命周期管理。

3、OSGi bundle生命周期

要想使用組件(bundle),就得使用生命周期層的API與OSGi框架的生命周期層進(jìn)行交互。
OSGi框架的核心并沒(méi)有強(qiáng)制使用任何特定的API交互機(jī)制(比如命令行,GUI,或者XML配置文件等),只是單純的Java API而已,開(kāi)發(fā)者可以任意創(chuàng)造出自己想要的交互模式,保證了框架的靈活性。
在標(biāo)準(zhǔn)的Java編程中,會(huì)通過(guò)將jar包放到classpath中來(lái)使用jar包,而bundle不同。Bundle只有在被安裝(install)到一個(gè)OSGi框架的運(yùn)行實(shí)例中才能用起來(lái),并且OSGi框架支持對(duì)bundle完整的生命周期管理,并且支持這些管理操作在應(yīng)用執(zhí)行完成,其動(dòng)態(tài)性可見(jiàn)一斑。
Bundle生命周期的狀態(tài)轉(zhuǎn)移圖如下:
架構(gòu)設(shè)計(jì)——OSGI規(guī)范
可以通過(guò)Bundle的getState方法來(lái)獲得bundle的當(dāng)前狀態(tài)。
Starting和Stopping狀態(tài)是暫態(tài),在持續(xù)一會(huì)兒后就會(huì)自動(dòng)轉(zhuǎn)移到下一個(gè)狀態(tài),不需要轉(zhuǎn)移條件。

4、生命周期層API

生命周期層的API主要由BundleActivator、BundleContext、Bundle三個(gè)核心接口組成。
A、BundleActivator
BundleActivator讓開(kāi)發(fā)者能夠捕捉bundle的start和stop事件,并對(duì)作出自定義的反應(yīng)。
BundleActivator的接口定義如下:

public interface BundleActivator {
    public void start(BundleContext context) throws Exception;
    public void stop(Bundlecontext context) throws Exception;
}

如果一個(gè)類實(shí)現(xiàn)了BundleActivator接口,那么類就成為一個(gè)Activator。但有實(shí)現(xiàn)是不夠的,要讓OSGi框架知道Activator的存在。所以還需要在MANIFEST文件中添加如下一項(xiàng)屬性:
Bundle-Activator:org.demo.Activator
當(dāng)bundle啟動(dòng)(start)的時(shí)候,OSGi框架就會(huì)調(diào)用Activator的start方法,同樣的也適用與stop方法。
并不是每個(gè)bundle都需要一個(gè)activator,有時(shí)候bundle只是為了和其它bundle分享代碼,而并不需要在啟動(dòng)和停止的時(shí)候做出多余的動(dòng)作。是否使用BundleActivator借口,需要具體問(wèn)題具體分析。
B、BundleContext
BundleContext是bundle在框架中的執(zhí)行時(shí)上下文,提供了與框架進(jìn)行交互的方法。
BundleContext接口中的方法主要分為兩類,一類與部署和生命周期管理相關(guān),另一類是關(guān)于利用服務(wù)層進(jìn)行bundle間交互的方法。

public interface BundleContext {
    String getProperty(String key);
    Bundle getBundle();
    Bundle installBundle(String location, InputStream input) throws BundleException;
    Bundle installBundle(String location) throws BundleException;
    Bundle getBundle(long id);
    Bundle[] getBundles();
    void addBundleListener(BundleListener listener);
    void removeBundleListener(BundleListener listener);
    void addFrameworkListener(FrameworkListener listener);
    void removeFrameworkListener(FrameworkListener listener);
}  

BundleContext接口對(duì)于與其相關(guān)的bundle來(lái)說(shuō)都是唯一的執(zhí)行上下文,并且只有在bundle是屬于active狀態(tài)的時(shí)候執(zhí)行時(shí)上下文才是有意義的,即在start方法被調(diào)用和stop方法被調(diào)用的兩個(gè)時(shí)間點(diǎn)之間。如果一個(gè)bundle沒(méi)有處于active時(shí)間段,但組件的bundlecontext對(duì)象被使用,框架會(huì)拋出異常。
框架使用這個(gè)上下文對(duì)象還有一個(gè)目的就是為了bundle的安全和資源分配,所以BundleContext對(duì)象應(yīng)該被當(dāng)做私有對(duì)象,不應(yīng)該被隨意在bundle之間傳遞。
C、Bundle
Bundle在邏輯上表示一個(gè)bundle,OSGi環(huán)境中的一個(gè)物理bundle對(duì)應(yīng)一個(gè)bundle對(duì)象。bundle對(duì)象中包含了bundle的基本信息和bundle聲明周期的控制接口。
在BundleContext接口中,getBundle方法可以得到Bundle對(duì)象。
對(duì)于每個(gè)被安裝到框架中的bundle,框架都創(chuàng)建一個(gè)Bundle對(duì)象在邏輯上表達(dá)之。Bundle接口中定義了bundle生命周期管理的方法:

public interface Bundle {
    BundleContext getBundleContext();
    long getBundleId();
    Dictionary getHeaders();
    Dictionary getHeaders(String locale);
    String getLocation();
    int getState();
    String getSymbolicName();
    Version getVersion();
    void start(int options) throws BundleException;
    void start() throws BundleException;
    void stop(int options) throws BundleException;
    void stop() throws BundleException;
    void update(InputStream input) throws BundleException;
    void update() throws BundleException;
    void uninstall() throws BundleException;
}

大部分OSGi框架的實(shí)現(xiàn)都是將locatioin解釋為指向OSGi bundle的一個(gè)URL,在需要的時(shí)候就會(huì)通過(guò)URL將bundle下載到框架中來(lái)安裝使用。但OSGi標(biāo)準(zhǔn)沒(méi)有規(guī)定location的形式必須是URL,而且URL也并不是非要不可的,還可以通過(guò)輸入流(Input Stream)來(lái)安裝bundle。
bundle不能自己改變自己的狀態(tài),比如說(shuō)一個(gè)active的bundle不能stop自己,stop自己就會(huì)拋出異常。

五、服務(wù)層

1、服務(wù)簡(jiǎn)介

服務(wù)是服務(wù)提供者和服務(wù)使用者之間的一個(gè)契約。使用者一般不關(guān)心服務(wù)實(shí)現(xiàn)的細(xì)節(jié),只關(guān)心是否滿足契約(服務(wù)應(yīng)該提供什么功能,滿足什么格式)。使用服務(wù)的過(guò)程包含了發(fā)現(xiàn)服務(wù)和達(dá)成協(xié)議的形式,需要通過(guò)服務(wù)的標(biāo)志性特征來(lái)找到對(duì)應(yīng)的服務(wù)。

2、OSGI服務(wù)層

服務(wù)層是OSGi框架中最上面的一層,服務(wù)層帶來(lái)了更多的動(dòng)態(tài)性,并且使用了面向服務(wù)編程模型。當(dāng)一個(gè)bundle發(fā)現(xiàn)開(kāi)始使用OSGi中的一個(gè)服務(wù)后,服務(wù)可能在任何的時(shí)候改變或者是消失。
OSGi框架有一個(gè)中心化的注冊(cè)表,注冊(cè)表遵從publish-find-bind模型:
架構(gòu)設(shè)計(jì)——OSGI規(guī)范
一個(gè)提供服務(wù)的bundle可以發(fā)布POJO作為服務(wù)的實(shí)體;一個(gè)使用服務(wù)的bundle可以通過(guò)注冊(cè)表找到和綁定服務(wù)。
可以通過(guò)BundleContext接口來(lái)完成服務(wù)的發(fā)布、發(fā)現(xiàn)、綁定,如下:

public interface BundleContext {   
    void addServiceListener(ServiceListener listener, String filter) throws InvalidSyntaxException;  
    void addServiceListener(ServiceListener listener);  
    void removeServiceListener(ServiceListener listener);  
    ServiceRegistration registerService(String[] clazzes, Object service, Dictionary properties);   
    ServiceRegistration registerService(String clazz, Object service, Dictionary properties);  
    ServiceRegistration[] getServiceReferences(String clazz, String filter) throws InvalidSyntaxException;  
    ServiceRegistration[] getAllServiceReferences(String clazz, String filter) throws InvalidSyntaxException;  
    ServiceReference getServiceReference(String clazz);  
    Object getService(ServiceReference reference);  
    boolean ungetService(ServiceReference reference);  
}

3、發(fā)布服務(wù)

為了讓其它bundle能發(fā)現(xiàn)服務(wù),必須在發(fā)布服務(wù)前對(duì)其進(jìn)行特征描述。服務(wù)特征包括接口的名字(可以是名字的數(shù)組),接口的實(shí)現(xiàn)和一個(gè)可選的java.util.Dictionary類型的元數(shù)據(jù)信息。示例如下:

String[] interfaces =  new String[]{StockListing.class.getName(), StockChart.class.getname()};  
Dictionary metadata =  new Properties();  
metadata.setProperty(“name”, “LSE”);  
metadata.setProperty(“currency”, Currency.getInstance(“GBP”));  
metadata.setProperty(“country”, “GB”);  
ServiceRegistration registration = bundleContext.registerService(interfaces, new LSE(), metadata);

上述代碼中,通過(guò)ServiceRegistration對(duì)象可以更新服務(wù)的元數(shù)據(jù):
registration.setProperties(newMetadata);
可以直接將服務(wù)注銷:
registration.unregister();
ServiceRegistration對(duì)象不能和其它Bundles共享,因?yàn)镾erviceRegistration對(duì)象和發(fā)布服務(wù)的bundle的生命周期相互依存。如果bundle已經(jīng)不在框架執(zhí)行環(huán)境中存在,那么ServiceRegistration對(duì)象也不應(yīng)該存在。
代碼中的參數(shù)new LSE()是一個(gè)POJO,不需要實(shí)現(xiàn)任何OSGi類型或者使用標(biāo)注,只要滿足服務(wù)約定就可以。
如果在刪除發(fā)布的服務(wù)前bundle以及停止,框架會(huì)幫助刪除服務(wù)。

4、發(fā)現(xiàn)服務(wù)

可以根據(jù)服務(wù)約定從注冊(cè)表中找到正確的服務(wù)。發(fā)現(xiàn)服務(wù)并獲得其引用的接口如下:

ServiceReference reference =  
bundleContext.getServiceReference(StockListing.class.getName());  

reference是服務(wù)對(duì)象的間接引用,不直接使用服務(wù)對(duì)象是為了將服務(wù)的使用和服務(wù)的實(shí)現(xiàn)進(jìn)行解耦,將服務(wù)注冊(cè)表作為兩者的中間人,達(dá)到跟蹤和控制服務(wù)的目的,同時(shí)還可以在服務(wù)消失后通知使用者。
ServiceReference可以在bundle之間互享,與使用服務(wù)的bundle的生命周期無(wú)關(guān)。
在getServiceReference方法中,選擇service的默認(rèn)優(yōu)先級(jí)是先選擇service.rank最高的,在rank相等的情況下選擇最早在框架中注冊(cè)的。除了默認(rèn)的規(guī)則,還可以在getServiceReferences中通過(guò)添加過(guò)濾參數(shù)(作為調(diào)用該方法的第二個(gè)參數(shù))來(lái)做一些篩選。

ServiceReference[] references = 
bundleContext.getServiceReferences(StockListing.class.getName(), “(&(currency=GBP)(objectClass=org.example.StockChart))”);

匹配參數(shù)是一個(gè)字符串,字符串的格式屬于LDAP查詢格式,在RFC1960標(biāo)準(zhǔn)中有完整的描述。
字符串中等號(hào)左邊的內(nèi)容是元數(shù)據(jù)(Dictionary)中的左值,通過(guò)左值對(duì)應(yīng)的右值與服務(wù)的元數(shù)據(jù)進(jìn)行匹配。匹配示例如下:
屬性匹配:

(name=John Smith) 
(age>=20) 
(age<=65) 

模糊匹配:
(name~=johnsmith)
通配符匹配:
(name=Jo*n*Smith*)
判斷某個(gè)屬性是否存在:
(name=)
條件與:
(&(name=John Smith)(occupation=doctor))
條件或:
(|(name~=John Smith)(name~=Smith John))
*條件非: **
(!(name=John Smith))

5、綁定和使用服務(wù)

發(fā)現(xiàn)服務(wù)后,使用服務(wù)之前,必須從注冊(cè)表中綁定實(shí)現(xiàn)的服務(wù)。

StockListing listing = 
(StockListing) bundleContext.getService(reference);

返回的POJO實(shí)例和在注冊(cè)表中注冊(cè)的實(shí)例是同一個(gè)。
每次使用getService方法的時(shí)候,注冊(cè)表會(huì)將對(duì)應(yīng)服務(wù)的使用次數(shù)加1,同時(shí)會(huì)記錄誰(shuí)在使用該服務(wù)。如果不想使用服務(wù)的,注銷服務(wù)。

bundleContext.ungetService(reference);  
listing = null;  

六、OSGI的實(shí)現(xiàn)

1、OSGI的具體實(shí)現(xiàn)

OSGI是OSGi Alliance組織制定的Java模塊化規(guī)范,但OSGI聯(lián)盟并沒(méi)有給出OSGI容器的實(shí)現(xiàn),具體實(shí)現(xiàn)由第三方廠商完成,目前使用較多的OSGI容器有Apache Felix、Equinox、Spring DM。

2、OSGI的JAVA實(shí)現(xiàn)

A、Apache Felix
Apache Felix是Apache旗下的一個(gè)OSGi框架,F(xiàn)elix是一個(gè)OSGi版本4規(guī)范的Apache實(shí)現(xiàn)。Apache Felix提供的服務(wù)幾乎涵蓋了全部的OSGi 4.2的標(biāo)準(zhǔn),除此之外還提供了一些非標(biāo)準(zhǔn)的功能,例如iPOJO。Apache Felix框架本身非常緊湊,只需要3個(gè)包加一個(gè)shell就可以運(yùn)行,無(wú)論是開(kāi)發(fā)還是Debug都非常簡(jiǎn)便。
B、Equinox
Equinox是Eclipse旗下的OSGi框架,本身也被Eclipse采用,是Eclipse的PDE開(kāi)發(fā)環(huán)境的底層。Equinox本身也是相當(dāng)?shù)娜娴目蚣?,提供的功能不比Felix少多少。Equinox被當(dāng)做開(kāi)發(fā)Eclipse Plugin的應(yīng)用較多,如果要開(kāi)發(fā)一個(gè)Web程序,就會(huì)感到功能和文檔不夠全面。Equinox最大的優(yōu)勢(shì)在于和Eclipse結(jié)合緊密,只要安裝了PDE,就已經(jīng)有了Equinox,可以方便的在Eclipse里設(shè)置開(kāi)發(fā)的Bundle,啟動(dòng)、部署等操作也異常簡(jiǎn)單,而且有專門的Debug界面。
C、Spring DM
Spring DM是Spring旗下的OSGi框架,Spring DM的最大特點(diǎn)是結(jié)合了Spring框架。
D、Knopflerfish
Knopflerfish是OSGi的先行者,是一個(gè)相當(dāng)標(biāo)準(zhǔn)OSGi框架,提供了絕大多數(shù)標(biāo)準(zhǔn)功能。

3、OSGI的C++實(shí)現(xiàn)

A、CTK Plugin Framework
CTK是基于Qt開(kāi)發(fā)的支持生物醫(yī)學(xué)影像計(jì)算的開(kāi)源項(xiàng)目。
CTK中的CTK Plugin Framework模塊借鑒了OSGI的思想,并實(shí)現(xiàn)了幾乎完整的OSGI框架API。
B、C++ Micro Services
C++ Micro Services是基于OSGI思想的用于創(chuàng)建和管理模塊化軟件系統(tǒng)的C++庫(kù)。

4、OSGI的C實(shí)現(xiàn)

Apache Celix是基于C/C++的OSGI規(guī)范實(shí)現(xiàn),提供了一個(gè)使用組件和面向服務(wù)編程(SOP)開(kāi)發(fā)模塊化應(yīng)用的框架。
Apache Celix主要使用C語(yǔ)言開(kāi)發(fā),為了支持C++,以庫(kù)的形式增加了抽象。
官方網(wǎng)站:http://celix.apache.org/

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI