gembin

          OSGi, Eclipse Equinox, ECF, Virgo, Gemini, Apache Felix, Karaf, Aires, Camel, Eclipse RCP

          HBase, Hadoop, ZooKeeper, Cassandra

          Flex4, AS3, Swiz framework, GraniteDS, BlazeDS etc.

          There is nothing that software can't fix. Unfortunately, there is also nothing that software can't completely fuck up. That gap is called talent.

          About Me

           

          OSGi Declarative Services簡介

          在 OSGi 服務(wù)平臺(tái)上構(gòu)建應(yīng)用時(shí),必須考慮各種服務(wù)之間依賴關(guān)系及服務(wù)的管理,應(yīng)用所依賴的服務(wù)有可能在任何時(shí)候被注銷或者更新,用戶在完成對(duì) Service 的發(fā)布、查找、綁定的同時(shí),還需要對(duì)服務(wù)的狀態(tài)進(jìn)行監(jiān)聽,以便作出適當(dāng)?shù)捻憫?yīng),所以在 OSGi 服務(wù)平臺(tái)上,對(duì)服務(wù)依賴關(guān)系的動(dòng)態(tài)管理至關(guān)重要。在 OSGi Release 4 中,提出了 Declarative Services 規(guī)范,通過該規(guī)范可以方便地對(duì)服務(wù)之間的依賴關(guān)系和狀態(tài)進(jìn)行監(jiān)聽和管理。在本文中,將對(duì) Declarative Services 規(guī)范進(jìn)行介紹并且基于該規(guī)范開發(fā)一個(gè)實(shí)例。

          Declarative Services簡介

          Declarative Services 是一個(gè)面向服務(wù)的組件模型,它制訂的目的是更方便地在 OSGi 服務(wù)平臺(tái)上發(fā)布、查找、綁定服務(wù),對(duì)服務(wù)進(jìn)行動(dòng)態(tài)管理,如監(jiān)控服務(wù)狀態(tài)以及解決服務(wù)之間的復(fù)雜的依賴關(guān)系等問題。Declarative Services 采用服務(wù)組件的延遲加載以及組件生命周期管理的方式來控制對(duì)于內(nèi)存的占用以及啟動(dòng)的快速,很好的解決了傳統(tǒng)的 OSGi 服務(wù)模型在開發(fā)和部署比較復(fù)雜應(yīng)用時(shí)內(nèi)存占用大、啟動(dòng)慢等問題,并且對(duì)服務(wù)組件的描述采用XML來實(shí)現(xiàn),十分便于用戶理解和使用。在 Declarative Services 中,Component 可以是 Service 的提供者和引用者,一個(gè) Component 可以提供 0 至多個(gè) Service,也可以引用 0 至多個(gè) Service,并且采用component 方式封裝 Service,方便了對(duì) Service 的復(fù)用,從開發(fā)者的角度來看,該服務(wù)組件模型簡化了在 OSGi 服務(wù)平臺(tái)中的編程模型。Declarative Services 規(guī)范參考了"Automating Service Dependency Management in a Service-Oriented Component Model"一文的有關(guān)概念,讀者可從參考資料獲得該文的詳細(xì)信息。


          Component Satisfied 概念介紹

          在 Declarative Services 中,一個(gè)服務(wù)組件是包含在 Bundle 應(yīng)用中的普通的 Java 類,每個(gè)Component 可以暴露出多個(gè)服務(wù),同時(shí)也可依賴于多個(gè)服務(wù),通過XML文件描述和服務(wù)組件相關(guān)的信息,SCR(Service Component Runtime)根據(jù)服務(wù)組件配置文件控制著組件配置的激活(Activate)和鈍化(Deactivate),服務(wù)組件配置文件包括如組件的類型、組 件的實(shí)現(xiàn)以及引用的服務(wù)等信息。在詳細(xì)介紹服務(wù)組件(Component)之前,我們必須了解 Component Satisfied 的概念,在 Declarative Services 中,Component Satisfied 與 Component 的生命周期密切相關(guān)。如 Component 激活的前提條件之一就是 Component Satisfied,而在 Component 的運(yùn)行過程中,出現(xiàn) Unsatisfied 時(shí),Component 將被鈍化。主要由以下兩點(diǎn)決定 Component 是否處于Satisfied 狀態(tài):

          Component 為 Enabled 狀態(tài),Component 的生命周期包含在引用它的 Bundle 應(yīng)用的生命周期之內(nèi),只有在 Bundle 處于 Active 狀態(tài)時(shí),Component 才有可能為 Enabled 狀態(tài),在 Bundle處于 Stop 狀態(tài)時(shí),Bundle 中所有的 Component 都處在 Disabled 狀態(tài)。Component 初始的Enabled 狀態(tài)可以在服務(wù)組件配置文件中設(shè)定。

          Component 的配置是可以被引用和解析的,Component 中引用的 Service 也是 Satisfied 的,引用的 Service 至少有一個(gè)是處于可用狀態(tài)的,或者引用的 Service 在服務(wù)組件配置文件里配置了可為 0 個(gè)可用狀態(tài)的 Service。

          當(dāng)上述兩個(gè)條件中任何一個(gè)不滿足時(shí),組件配置將變?yōu)?Unsatisfied 狀態(tài),組件配置將被鈍化。在理解 Component Satisfied 的概念后,下面講解三種類型的服務(wù)組件。


          Component 介紹

          在 Bundle 啟動(dòng)時(shí), Declarative Services 裝載相應(yīng)的服務(wù)組件配置文件,配置文件在MAINFEST.MF 文件的 Service-Component 屬性指定,解析配置文件,獲取服務(wù)組件引用的 Service ,如果判斷組件 Satisfied 狀態(tài)的兩個(gè)條件滿足時(shí), Declarative Services 就認(rèn)為這個(gè)組件是 Satisfied 的。

          Immediate Component

          對(duì)于 Immediate Component,如果組件配置處于 Satisfied 狀態(tài),將會(huì)立即被激活,并且如果該配置指定了服務(wù),那么 SCR 會(huì)注冊(cè)該服務(wù)并且立即激活該服務(wù)組件。在 SCR 激活組件配置時(shí),實(shí)現(xiàn)服務(wù)組件類的 activate 方法將會(huì)被調(diào)用,在SCR鈍化組件配置時(shí),deactivate方法將會(huì)被調(diào)用。Immediate Component的狀態(tài)圖如圖1所示:


          圖示1:Immediate Component狀態(tài)圖
          圖示1:Immediate Component狀態(tài)圖

          Delayed Component

          對(duì)于 Delayed Component ,如果組件配置處于Satisfied狀態(tài),該組件并不會(huì)立即被激活,Declarative Services 會(huì)根據(jù)組件配置文件中的 Service 的配置,注冊(cè)相應(yīng)的Service 的信息,直到該服務(wù)組件被請(qǐng)求時(shí), Declarative Services 才會(huì)激活該組件配置 。 Delayed Component 延遲了 Component 類的創(chuàng)建,當(dāng)該服務(wù)組件的服務(wù)收到請(qǐng)求時(shí),該 Component 類的 activate 方法才會(huì)被調(diào)用。如果一個(gè) Component 不是 Factory Component,并且在其組件配置文件中指定了服務(wù),組件的 immediate 屬性設(shè)置為 false,那么該組件就是 Delayed Component。Delayed Component 的狀態(tài)圖如圖 2 所示:


          圖示2:Delayed Component 狀態(tài)圖
          圖示2:Delayed Component 狀態(tài)圖

          Factory Component

          通過在組件配置文件中設(shè)置 Component 的 factory 屬性,將 Component 聲明為 Factory Component。該組件在激活后注冊(cè)的是一個(gè) Component Factory 服務(wù),只有在調(diào)用 Component Factory 的 newInstance 方法后才會(huì)激活相應(yīng)的各個(gè)組件,每一次調(diào)用 newInstance 方法,都會(huì)創(chuàng)建和激活一個(gè)新的組件配置。如果在組件配置文件中聲明了服務(wù),那么在該組件激活之前,聲明的服務(wù)被注冊(cè)。Factory Component 的狀態(tài)圖如圖3所示:


          圖示3:Factory Component狀態(tài)圖
          圖示3:Factory Component狀態(tài)圖

          在三種類型的服務(wù)組件中,Delayed Component 很好的解決了系統(tǒng)服務(wù)的動(dòng)態(tài)性問題,同時(shí)也節(jié)省了內(nèi)存的占用。 服務(wù)組件的生命周期受 Bundle 生命周期影響,當(dāng) Bundle 停止時(shí),那么Bundle 中所有的服務(wù)組件也就停止。


          Service 的發(fā)布、查找、綁定

          在 OSGi 服務(wù)平臺(tái)中,大部分 Bundle 應(yīng)用都是基于服務(wù)的,服務(wù)的發(fā)布、引用十分重要,下面講一下利用服務(wù)組件如何進(jìn)行 Service 的發(fā)布、查找和綁定。

          Service 的發(fā)布

          對(duì)于 Component 中 Service 的發(fā)布,需要在組件配置文件中定義 service 元素,該 service元素至少包括一個(gè)或多個(gè) provide 元素,該 provide 元素定義了該 component 提供的服務(wù)接口,它只有一個(gè)屬性 interface,該 interface 定義了提供服務(wù)的接口,并且允許是實(shí)現(xiàn)該服務(wù)接口的類名??梢钥闯?,利用 Declarative Services 發(fā)布 Service 非常簡單,只要 Component 實(shí)現(xiàn)了定義的 Service 的接口即可。如在本文所講解例子中,在組件配置文件中,聲明姓名查詢服務(wù)如圖 4 所示:


          圖示4:姓名查詢服務(wù)聲明
          圖示4:姓名查詢服務(wù)聲明

          Service 的查找和綁定

          在 Declarative Services 中,Component 所引用的服務(wù),稱為 Target Service,當(dāng) Component 中引用的 Target Service 也是 Satisfied 時(shí),即引用的 Service 至少有一個(gè)是處于可用狀態(tài)的,或者引用的 Service 在服務(wù)組件配置文件里配置了可為 0 個(gè)可用狀態(tài)的 Service,組件配置才有可能被激活。在組件實(shí)現(xiàn)類中,有兩種策略可以獲得在組件配置文件里指定的 Target Service,是事件策略和 Lookup 策略。

          事件策略

          在服務(wù)組件激活的過程中,SCR 必須將組件配置文件里指定的 Target Service 綁定到組件配置中。在事件策略中,SCR 通過調(diào)用組件實(shí)現(xiàn)類的一個(gè)方法將 Target Service 綁定到組件中,同樣,SCR 通過調(diào)用另外一個(gè)方法來取消綁定,這些方法在組件配置文件中 reference 元素的bind 和 unbind 屬性指定。事件策略主要適用于服務(wù)組件所引用的 Target Service 處在動(dòng)態(tài)變化中。如在本文例子中,如果采用事件策略引用姓名查詢服務(wù),在配置文件中聲明和 Component 實(shí)現(xiàn)類中引用服務(wù)分別如圖示 5、圖示 6 所示:


          圖示5:采用事件策略的組件配置文件
          圖示5:采用事件策略的組件配置文件

          圖示 6:采用事件策略的綁定姓名查詢服務(wù)
          圖示 6:采用事件策略的綁定姓名查詢服務(wù)

          Lookup 策略

          在組件實(shí)現(xiàn)類中,通過調(diào)用 ComponentContext 的 locateService 方法來定位所引用的 Target Service ,該方法的參數(shù)是在組件配置文件里指定的 reference 元素的 name 屬性。如在本文例子中,如果采用 Lookup 策略引用姓名查詢服務(wù),在配置文件中聲明和 Component實(shí)現(xiàn)類中引用服務(wù)分別如圖示 7、圖示 8 所示:


          圖示7:采用 Lookup 策略的組件配置文件
          圖示7:采用 Lookup 策略的組件配置文件

          圖示 8:采用 Lookup 策略的引用姓名查詢服務(wù)
          圖示 8:采用 Lookup 策略的引用姓名查詢服務(wù)

          在 OSGi 服務(wù)平臺(tái)中,即便 Component 已經(jīng)綁定所引用的 Target Service,但是由于服務(wù)的動(dòng)態(tài)性,它可能在任何時(shí)刻被注冊(cè)、替換或者注銷,這些變化可能使服務(wù)組件所引用的 Target Service 變成過時(shí)的引用,所以,在 Declarative Services 中,當(dāng)這些情況發(fā)生時(shí),Component必須采取某種策略去處理這些變化。Declarative Services 提供兩種策略,一種是 static 策略 ,另外一種是 dynamic 策略 ,默認(rèn)情況下 Component 采用的是 static 策略。當(dāng)采用static 策略時(shí),如果引用的 Target Service 發(fā)生了變化,那么組件配置會(huì)被重新裝載并激活。當(dāng)采用 dynamic 策略時(shí),SCR 在不鈍化組件配置的情況下可以改變綁定的 Target Service。此外,Declarative Services 還提供很多功能,如可通過在 Component 的 reference 元素中增加 target 屬性來實(shí)現(xiàn)對(duì)所引用 Service 進(jìn)行過濾;如可增加 cardinality 屬性來對(duì)引用 Service 的數(shù)量進(jìn)行控制。關(guān)于 Declarative Services 更詳細(xì)的信息,請(qǐng)讀者參見本文的參考資料。


          使用 Eclipse 開發(fā)服務(wù)組件

          在本文中,我們結(jié)合 Equinox 項(xiàng)目關(guān)于 Declarative Services 的實(shí)現(xiàn),開發(fā)兩個(gè)使用服務(wù)組件的 Bundle 應(yīng)用,其中第一個(gè) Bundle 的服務(wù)組件的配置文件中聲明注冊(cè)了一個(gè)姓名查詢服務(wù),用于判斷所給姓名是否在已定義的查詢列表中;第二個(gè) Bundle 應(yīng)用的服務(wù)組件的配置文件中靜態(tài)引用了第一個(gè) Bundle 應(yīng)用服務(wù)組件所注冊(cè)的姓名查詢服務(wù),如果用戶所給的姓名包含在查詢列表中,將返回正確的信息。最后,將開發(fā)的 Bundle 應(yīng)用部署的 Equinox OSGi 框架中,用戶可以在 OSGi 控制命令行中輸入命令來查詢關(guān)于框架和 Bundle 應(yīng)用的具體信息。讀者可以從參考資料中獲得本文 Bundle 應(yīng)用的源代碼。關(guān)于 Equinox 項(xiàng)目的詳細(xì)信息,請(qǐng)查閱參考資料信息。

          (1)首先定義所提供服務(wù)的接口,然后 Bundle 應(yīng)用的服務(wù)組件實(shí)現(xiàn)這個(gè)服務(wù)接口。在本例中,定義姓名查詢接口 NameService.java。下面是該接口的源代碼:


          NameService Interface 源代碼
          package ds.example.service;
          /**
          * A simple service interface that defines a name service.
          * A name service simply verifies the existence of a Name.
          **/
          public interface NameService {
          /**
          * Check for the existence of a Name.
          * @param name the Name to be checked.
          * @return true if the Name is in the list,
          * false otherwise.
          **/
          public boolean checkName(String name);
          }

          該服務(wù)接口很簡單,只包含一個(gè)需要實(shí)現(xiàn)的方法。通常為了將服務(wù)接口和服務(wù)實(shí)現(xiàn)相分離,要將該服務(wù)接口單獨(dú)放在一個(gè)包內(nèi)。

          (2 ) 定義 Bundle 描述文件 MANIFEST.MF,Bundle 應(yīng)用 dsExample 的 MANIFEST.MF 文件如下:


          MANIFEST.MF 文件信息
          Manifest-Version: 1.0
          Bundle-ManifestVersion: 2
          Bundle-Name: DsExample Service
          Bundle-SymbolicName: dsExample
          Bundle-Version: 1.0.0
          Bundle-Localization: plugin
          Import-Package: org.osgi.framework;version="1.3.0",
          org.osgi.service.component;version="1.0.0"
          Service-Component: OSGI-INF/component.xml
          Export-Package: ds.example.service

          其中,Service-Component 屬性指定了該 Bundle 應(yīng)用的服務(wù)組件配置文件,在該配置文件中聲明服務(wù)并且指定了實(shí)現(xiàn)該服務(wù)的組件;Export-Package 屬性指定了該 Bundle 輸出的共享包,該屬性可以使其他的 Bundle 應(yīng)用引用所定義的服務(wù)接口。

          (3)編輯該 Bundle 應(yīng)用的服務(wù)組件配置文件,正如前面所講 Service 的發(fā)布那樣,該服務(wù)組件的配置文件如下:


          dsExample Bundle 的組件配置文件
          <?xml version="1.0" encoding="UTF-8"?>
          <component name="dsExample">
          <implementation
          class="example.osgi.NameImpl"/>
          <service>
          <provide interface="ds.example.service.NameService"/>
          </service>
          </component>

          其中,Service 元素定義了所提供服務(wù)的接口;Implementation 元素定義了實(shí)現(xiàn)該服務(wù)接口的組件類名。

          (4)實(shí)現(xiàn)在服務(wù)組件配置文件中指定的服務(wù)組件,源代碼如下所示: dsExample 實(shí)現(xiàn)組件源代碼


          public class
          NameImpl
          implements NameService {
          // The set of names contained in the arrays.
          String[] m_name =
          { "Marry", "John", "David", "Rachel", "Ross" };

          protected void activate(ComponentContext context) {
          System.out.println("NameService Component Active,within the bundle
          lifecircle.");
          }
          public void
          deactivate(ComponentContext context)
          throws Exception {
          System.out.println("NameService Component Deactive,within the bundle
          lifecircle.");
          }
          public boolean checkName(String name) {
          // This is very inefficient
          for
          (
          int i = 0; i < m_name.length; i++)
          {
          if (m_name[i].equals(name))
          {
          return true;
          }
          }
          return false;
          }
          }

          該服務(wù)組件實(shí)現(xiàn)了 NameService 接口,并且在服務(wù)組件激活和鈍化時(shí)分別打印出相應(yīng)信息,以便在運(yùn)行 Bundle 應(yīng)用時(shí),能夠跟蹤 Component 的生命周期。

          (5)創(chuàng)建項(xiàng)目名為 dsExampleClient 的 Bundle 應(yīng)用,該應(yīng)用的服務(wù)組件在 OSGi 平臺(tái)上查詢并引用 dsExample Bundle 應(yīng)用已經(jīng)注冊(cè)的姓名查詢服務(wù),然后從標(biāo)準(zhǔn)輸入讀入用戶所輸入的姓名信息,判斷所輸入姓名是否有效。關(guān)于 dsExampleClient 應(yīng)用,讀者可從參考資料中獲得完整源代碼,下面只給出該 Bundle 應(yīng)用的服務(wù)組件配置文件:


          dsExampleClient Bundle 的組件配置文件
          <?xml version="1.0" encoding="UTF-8"?>
          <component name="dsExampleClient">
          <implementation
          class="exampleclient.osgi.CheckNameClient"/>
          <reference name="nameservice"
          interface="ds.example.service.NameService"
          cardinality="1..1"
          policy="static"
          />
          </component>

          其中,reference 元素定義了該組件所引用的服務(wù)接口,并且指明該組件采用 static 策略;Implementation 元素指定了實(shí)現(xiàn)組件的類。


          Bundle的部署及運(yùn)行

          在 Eclipse 平臺(tái)中,在菜單中選擇 Run-->Run AS-->Equinox FrameWork 來啟動(dòng) OSGi 服務(wù)平臺(tái)。注意在Equinox啟動(dòng)配置控制臺(tái)中的Target Platform 中選擇org.eclipse.equinox.ds選項(xiàng),該plug-in是Equinox關(guān)于Declarative Services的實(shí)現(xiàn),將兩個(gè)Bundle應(yīng)用設(shè)置為取消自動(dòng)啟動(dòng)選項(xiàng)。當(dāng)OSGi Equinox FrameWork啟動(dòng)后,在OSGi控制命令臺(tái)中輸入ss命令,可以查看OSGi服務(wù)平臺(tái)中已經(jīng)安裝的Bundle應(yīng)用信息及其狀態(tài)。如圖9所示,可以 看到dsExample和dsExampleClient Bundle應(yīng)用處于Resolved狀態(tài)。


          圖示9:Bundle狀態(tài)查詢
          圖示9:Bundle狀態(tài)查詢

          在OSGi控制命令臺(tái)中利用start命令啟動(dòng) dsExample 應(yīng)用,用ss命令查看啟動(dòng)后的Bundle應(yīng)用信息及其狀態(tài),可以看出 dsExample Bundle 處于Active狀態(tài),但是該Bundle的服務(wù)組件并沒有被激活,如果被激活,將會(huì)在OSGi控制命令臺(tái)中打印出"NameService Component Active,within the bundle lifecircle."字樣,說明該服務(wù)組件為 Delayed Component 類型,該組件并不會(huì)立即被激活,直到該服務(wù)組件被請(qǐng)求時(shí), Declarative Services 才會(huì)激活該組件配置,Delayed Component延遲了組件的加載,節(jié)省了內(nèi)存的占用 ,如圖10所示:


          圖示10:啟動(dòng)dsExample Bundle
          圖示10:啟動(dòng)dsExample Bundle

          在OSGi控制命令臺(tái)中利用start命令啟動(dòng)dsExampleClient應(yīng)用,可以看出兩個(gè) Bundle的服務(wù)組件相繼被激活,如圖11所示:


          圖示11:啟動(dòng)dsExampleClient Bundle
          圖示11:啟動(dòng)dsExampleClient Bundle

          在OSGi控制命令臺(tái)中利用stop命令停止dsExample應(yīng)用,可以看出兩個(gè) Bundle的服務(wù)組件相繼被鈍化,如圖12所示:


          圖示12:停止dsExample Bundle
          圖示12:停止dsExample Bundle

          需要注意的是服務(wù)組件的生命周期受 Bundle 生命周期的影響,當(dāng) Bundle 停止時(shí),那么Bundle 中所有的服務(wù)組件也就停止。


          總結(jié)

          Declarative Services 是一個(gè)面向服務(wù)的組件模型,其目的是更方便地在 OSGi 服務(wù)平臺(tái)上發(fā)布、查找、綁定服務(wù),對(duì)服務(wù)進(jìn)行動(dòng)態(tài)管理。Declarative Services 采用服務(wù)組件的延遲加載以及組件生命周期管理的方式來控制對(duì)于內(nèi)存的占用以及啟動(dòng)的快速,對(duì) Service 的動(dòng)態(tài)管理,使得系統(tǒng)可以根據(jù)系統(tǒng)運(yùn)行的情況做出及時(shí)的響應(yīng),增強(qiáng)了系統(tǒng)的穩(wěn)定性和靈活性。項(xiàng)目Gravity 也采用了類似的機(jī)制,有興趣的讀者可以參見參考資料中的詳細(xì)信息。

          posted on 2008-05-08 10:45 gembin 閱讀(1172) 評(píng)論(0)  編輯  收藏 所屬分類: OSGi

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(6)

          隨筆分類(440)

          隨筆檔案(378)

          文章檔案(6)

          新聞檔案(1)

          相冊(cè)

          收藏夾(9)

          Adobe

          Android

          AS3

          Blog-Links

          Build

          Design Pattern

          Eclipse

          Favorite Links

          Flickr

          Game Dev

          HBase

          Identity Management

          IT resources

          JEE

          Language

          OpenID

          OSGi

          SOA

          Version Control

          最新隨筆

          搜索

          積分與排名

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          free counters
          主站蜘蛛池模板: 通州市| 阿克苏市| 清水河县| 洞口县| 扶余县| 崇信县| 莱阳市| 合作市| 彰化市| 通河县| 荆门市| 永寿县| 河北省| 乌鲁木齐县| 孝感市| 远安县| 枝江市| 定南县| 佳木斯市| 花垣县| 舞钢市| 长岛县| 普兰店市| 伊宁县| 江陵县| 卓资县| 南投县| 尉氏县| 永济市| 林口县| 丰县| 台中市| 东安县| 上杭县| 高碑店市| 巩留县| 竹溪县| 昌黎县| 莆田市| 汉川市| 若尔盖县|